8282547: IGV: add control-flow graph view

Co-authored-by: Christian Hagedorn <chagedorn@openjdk.org>
Reviewed-by: chagedorn, xliu, thartmann
This commit is contained in:
Roberto Castañeda Lozano 2022-03-30 07:14:39 +00:00
parent 7418373674
commit edb42d7b0a
70 changed files with 2090 additions and 506 deletions
src/utils/IdealGraphVisualizer
ControlFlow/src/main/java/com/sun/hotspot/igv/controlflow
Data/src/main/java/com/sun/hotspot/igv/data
Filter/src/main/java/com/sun/hotspot/igv/filter
Graal/src/main/java/com/sun/hotspot/igv/graal/filters
Graph/src/main/java/com/sun/hotspot/igv/graph
HierarchicalLayout/src/main/java/com/sun/hotspot/igv/hierarchicallayout
Layout/src/main/java/com/sun/hotspot/igv/layout
ServerCompiler/src/main
java/com/sun/hotspot/igv/servercompiler
resources/com/sun/hotspot/igv/servercompiler
Settings/src/main/java/com/sun/hotspot/igv/settings
Util/src/main/java/com/sun/hotspot/igv/util
View/src/main

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -26,6 +26,7 @@ package com.sun.hotspot.igv.controlflow;
import com.sun.hotspot.igv.data.InputBlockEdge;
import com.sun.hotspot.igv.layout.Link;
import com.sun.hotspot.igv.layout.Port;
import com.sun.hotspot.igv.layout.Cluster;
import java.awt.BasicStroke;
import java.awt.Point;
import java.awt.Stroke;
@ -76,6 +77,14 @@ public class BlockConnectionWidget extends ConnectionWidget implements Link {
return outputSlot;
}
public Cluster getFromCluster() {
return null;
}
public Cluster getToCluster() {
return null;
}
public void setBold(boolean bold) {
this.isBold = bold;
updateStroke();

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -69,6 +69,14 @@ public class HierarchicalGraphLayout<N, E> extends GraphLayout<N, E> {
return to.getSlot();
}
public Cluster getFromCluster() {
return null;
}
public Cluster getToCluster() {
return null;
}
public List<Point> getControlPoints() {
return new ArrayList<Point>();
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -35,6 +35,7 @@ public class InputBlock {
private String name;
private InputGraph graph;
private Set<InputBlock> successors;
private boolean artificial;
@Override
public int hashCode() {
@ -77,6 +78,7 @@ public class InputBlock {
this.name = name;
nodes = new ArrayList<>();
successors = new LinkedHashSet<>(2);
artificial = false;
}
public String getName() {
@ -101,6 +103,10 @@ public class InputBlock {
return Collections.unmodifiableSet(successors);
}
public void setNodes(List<InputNode> nodes) {
this.nodes = nodes;
}
@Override
public String toString() {
return "Block " + this.getName();
@ -111,4 +117,12 @@ public class InputBlock {
successors.add(b);
}
}
void setArtificial(boolean artificial) {
this.artificial = artificial;
}
public boolean isArtificial() {
return artificial;
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -38,12 +38,14 @@ public class InputBlockEdge {
private InputBlock from;
private InputBlock to;
private State state = State.SAME;
private String label;
public InputBlockEdge(InputBlock from, InputBlock to) {
public InputBlockEdge(InputBlock from, InputBlock to, String label) {
assert from != null;
assert to != null;
this.from = from;
this.to = to;
this.label = label;
}
public InputBlock getFrom() {
@ -62,6 +64,10 @@ public class InputBlockEdge {
this.state = state;
}
public String getLabel() {
return label;
}
@Override
public boolean equals(Object obj) {
if (obj != null && obj instanceof InputBlockEdge) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -58,7 +58,11 @@ public class InputGraph extends Properties.Entity implements FolderElement {
}
public InputBlockEdge addBlockEdge(InputBlock left, InputBlock right) {
InputBlockEdge edge = new InputBlockEdge(left, right);
return addBlockEdge(left, right, null);
}
public InputBlockEdge addBlockEdge(InputBlock left, InputBlock right, String label) {
InputBlockEdge edge = new InputBlockEdge(left, right, label);
blockEdges.add(edge);
left.addSuccessor(right);
return edge;
@ -140,6 +144,7 @@ public class InputGraph extends Properties.Entity implements FolderElement {
public void clearBlocks() {
blocks.clear();
blockEdges.clear();
nodeToBlock.clear();
}
@ -168,7 +173,7 @@ public class InputGraph extends Properties.Entity implements FolderElement {
assert nodes.get(n.getId()) == n;
if (!scheduledNodes.contains(n)) {
if (noBlock == null) {
noBlock = this.addBlock("(no block)");
noBlock = addArtificialBlock();
}
noBlock.addNode(n.getId());
}
@ -270,6 +275,12 @@ public class InputGraph extends Properties.Entity implements FolderElement {
return sb.toString();
}
public InputBlock addArtificialBlock() {
InputBlock b = addBlock("(no block)");
b.setArtificial(true);
return b;
}
public InputBlock addBlock(String name) {
final InputBlock b = new InputBlock(this, name);
blocks.put(b.getName(), b);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -261,7 +261,7 @@ public class Parser implements GraphParser {
for (InputNode n : graph.getNodes()) {
if (graph.getBlock(n) == null) {
if (noBlock == null) {
noBlock = graph.addBlock("(no block)");
noBlock = graph.addArtificialBlock();
}
noBlock.addNode(n.getId());

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -78,7 +78,7 @@ public class ColorFilter extends AbstractFilter {
ConnectionStyle style = rule.getLineStyle();
for (OutputSlot s : f.getOutputSlots()) {
for (Connection c : s.getConnections()) {
for (FigureConnection c : s.getConnections()) {
if (color != null) {
c.setColor(color);
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -67,7 +67,7 @@ public class CombineFilter extends AbstractFilter {
InputSlot slot = null;
for (InputSlot s : succ.getInputSlots()) {
for (Connection c : s.getConnections()) {
for (FigureConnection c : s.getConnections()) {
if (c.getOutputSlot().getFigure() == f) {
slot = s;
}
@ -97,8 +97,8 @@ public class CombineFilter extends AbstractFilter {
}
for (InputSlot s : f.getInputSlots()) {
for (Connection c : s.getConnections()) {
Connection newConn = diagram.createConnection(slot, c.getOutputSlot(), c.getLabel(), c.getType());
for (FigureConnection c : s.getConnections()) {
FigureConnection newConn = diagram.createConnection(slot, c.getOutputSlot(), c.getLabel());
newConn.setColor(c.getColor());
newConn.setStyle(c.getStyle());
}
@ -115,7 +115,7 @@ public class CombineFilter extends AbstractFilter {
OutputSlot oldSlot = null;
for (OutputSlot s : f.getOutputSlots()) {
for (Connection c : s.getConnections()) {
for (FigureConnection c : s.getConnections()) {
if (c.getInputSlot().getFigure() == succ) {
oldSlot = s;
}
@ -155,8 +155,8 @@ public class CombineFilter extends AbstractFilter {
}
}
}
for (Connection c : nextSlot.getConnections()) {
Connection newConn = diagram.createConnection(c.getInputSlot(), slot, c.getLabel(), c.getType());
for (FigureConnection c : nextSlot.getConnections()) {
FigureConnection newConn = diagram.createConnection(c.getInputSlot(), slot, c.getLabel());
newConn.setColor(c.getColor());
newConn.setStyle(c.getStyle());
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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,7 +62,7 @@ public class ConnectionFilter extends AbstractFilter {
for (Figure f : figures) {
for (OutputSlot os : f.getOutputSlots()) {
for (Connection c : os.getConnections()) {
for (FigureConnection c : os.getConnections()) {
c.setStyle(rule.getLineStyle());
c.setColor(rule.getLineColor());
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022, 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
@ -64,7 +64,7 @@ public class EdgeColorIndexFilter extends AbstractFilter {
for (Slot slot : slots) {
if (index < colors.length && colors[index] != null) {
slot.setColor(colors[index]);
for (Connection c : slot.getConnections()) {
for (FigureConnection c : slot.getConnections()) {
c.setColor(colors[index]);
}

@ -0,0 +1,74 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package com.sun.hotspot.igv.filter;
import com.sun.hotspot.igv.graph.Diagram;
import com.sun.hotspot.igv.graph.Block;
import com.sun.hotspot.igv.graph.BlockSelector;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class RemoveBlockFilter extends AbstractFilter {
private final List<RemoveBlockRule> rules;
private final String name;
public RemoveBlockFilter(String name) {
this.name = name;
rules = new ArrayList<>();
}
@Override
public String getName() {
return name;
}
@Override
public void apply(Diagram diagram) {
for (RemoveBlockRule r : rules) {
List<Block> selected = r.getBlockSelector().selected(diagram);
Set<Block> toRemove = new HashSet<>(selected);
diagram.removeAllBlocks(toRemove);
}
}
public void addRule(RemoveBlockRule rule) {
rules.add(rule);
}
public static class RemoveBlockRule {
private final BlockSelector selector;
public RemoveBlockRule(BlockSelector selector) {
this.selector = selector;
}
public BlockSelector getBlockSelector() {
return selector;
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -58,9 +58,9 @@ public class RemoveInputsFilter extends AbstractFilter {
for (InputSlot is : f.getInputSlots()) {
if (z >= r.getStartingIndex() && z <= r.getEndIndex() && is.getConnections().size() > 0) {
StringBuilder sb = new StringBuilder();
List<Connection> conns = is.getConnections();
List<FigureConnection> conns = is.getConnections();
for (int i = 0; i < conns.size(); i++) {
Connection c = conns.get(i);
FigureConnection c = conns.get(i);
OutputSlot os = c.getOutputSlot();
Figure pred = os.getFigure();
if (i != 0) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -52,15 +52,15 @@ public class RemoveSelfLoopsFilter extends AbstractFilter {
for (InputSlot is : f.getInputSlots()) {
List<Connection> toRemove = new ArrayList<>();
for (Connection c : is.getConnections()) {
List<FigureConnection> toRemove = new ArrayList<>();
for (FigureConnection c : is.getConnections()) {
if (c.getOutputSlot().getFigure() == f) {
toRemove.add(c);
}
}
for (Connection c : toRemove) {
for (FigureConnection c : toRemove) {
c.remove();

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -54,7 +54,7 @@ public class SplitFilter extends AbstractFilter {
for (Figure f : list) {
for (InputSlot is : f.getInputSlots()) {
for (Connection c : is.getConnections()) {
for (FigureConnection c : is.getConnections()) {
OutputSlot os = c.getOutputSlot();
if (f.getSource().getSourceNodes().size() > 0) {
os.getSource().addSourceNodes(f.getSource());
@ -71,7 +71,7 @@ public class SplitFilter extends AbstractFilter {
}
}
for (OutputSlot os : f.getOutputSlots()) {
for (Connection c : os.getConnections()) {
for (FigureConnection c : os.getConnections()) {
InputSlot is = c.getInputSlot();
if (f.getSource().getSourceNodes().size() > 0) {
is.getSource().addSourceNodes(f.getSource());

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022, 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
@ -25,7 +25,7 @@ package com.sun.hotspot.igv.graal.filters;
import com.sun.hotspot.igv.data.Properties;
import com.sun.hotspot.igv.filter.AbstractFilter;
import com.sun.hotspot.igv.graph.Connection;
import com.sun.hotspot.igv.graph.FigureConnection;
import com.sun.hotspot.igv.graph.Diagram;
import com.sun.hotspot.igv.graph.Figure;
import com.sun.hotspot.igv.graph.InputSlot;
@ -42,7 +42,7 @@ public class GraalCFGFilter extends AbstractFilter {
@Override
public void apply(Diagram d) {
Set<Connection> connectionsToRemove = new HashSet<>();
Set<FigureConnection> connectionsToRemove = new HashSet<>();
for (Figure f : d.getFigures()) {
Properties p = f.getProperties();
@ -57,7 +57,7 @@ public class GraalCFGFilter extends AbstractFilter {
}
for (InputSlot is : f.getInputSlots()) {
if (is.getPosition() >= predCount && !"EndNode".equals(is.getProperties().get("class"))) {
for (Connection c : is.getConnections()) {
for (FigureConnection c : is.getConnections()) {
if (!"EndNode".equals(c.getOutputSlot().getFigure().getProperties().get("class"))) {
connectionsToRemove.add(c);
}
@ -66,7 +66,7 @@ public class GraalCFGFilter extends AbstractFilter {
}
}
for (Connection c : connectionsToRemove) {
for (FigureConnection c : connectionsToRemove) {
c.remove();
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022, 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
@ -23,16 +23,10 @@
*/
package com.sun.hotspot.igv.graal.filters;
import com.sun.hotspot.igv.data.Properties;
import com.sun.hotspot.igv.filter.AbstractFilter;
import com.sun.hotspot.igv.graph.Connection;
import com.sun.hotspot.igv.graph.Connection.ConnectionStyle;
import com.sun.hotspot.igv.graph.Diagram;
import com.sun.hotspot.igv.graph.Figure;
import com.sun.hotspot.igv.graph.InputSlot;
import java.awt.Color;
import java.util.HashMap;
import java.util.List;
/**
* Filter that colors usage and successor edges differently.
@ -54,29 +48,6 @@ public class GraalEdgeColorFilter extends AbstractFilter {
@Override
public void apply(Diagram d) {
List<Figure> figures = d.getFigures();
for (Figure f : figures) {
for (InputSlot is : f.getInputSlots()) {
for (Connection c : is.getConnections()) {
String type = c.getType();
if (type == "Association" && "EndNode".equals(c.getOutputSlot().getFigure().getProperties().get("class"))) {
type = "Successor";
}
if (type != null) {
Color typeColor = usageColor.get(type);
if (typeColor == null) {
c.setColor(otherUsageColor);
} else {
c.setColor(typeColor);
}
if (c.getStyle() != ConnectionStyle.DASHED && type == "Successor") {
c.setStyle(ConnectionStyle.BOLD);
}
}
}
}
}
}
public Color getUsageColor(String type) {

@ -0,0 +1,46 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package com.sun.hotspot.igv.graph;
import java.util.List;
import java.util.ArrayList;
// Selects blocks where any node is selected.
public class AnySelector implements BlockSelector {
private final Selector selector;
public AnySelector(Selector s) {
this.selector = s;
}
@Override
public List<Block> selected(Diagram d) {
List<Block> l = new ArrayList<>();
for (Figure f : selector.selected(d)) {
l.add(d.getBlock(f.getBlock()));
}
return l;
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -23,6 +23,7 @@
*/
package com.sun.hotspot.igv.graph;
import java.awt.Dimension;
import com.sun.hotspot.igv.data.InputBlock;
import com.sun.hotspot.igv.layout.Cluster;
import java.awt.Rectangle;
@ -55,11 +56,17 @@ public class Block implements Cluster {
public Set<? extends Cluster> getSuccessors() {
Set<Block> succs = new HashSet<Block>();
for (InputBlock b : inputBlock.getSuccessors()) {
succs.add(diagram.getBlock(b));
if (diagram.hasBlock(b)) {
succs.add(diagram.getBlock(b));
}
}
return succs;
}
public Dimension getNodeOffset() {
return new Dimension(0, -Figure.getVerticalOffset());
}
public void setBounds(Rectangle r) {
this.bounds = r;
}

@ -0,0 +1,112 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package com.sun.hotspot.igv.graph;
import com.sun.hotspot.igv.layout.Port;
import java.awt.Color;
import java.awt.Point;
import java.util.List;
public class BlockConnection implements Connection {
private final Block sourceBlock;
private final Block destinationBlock;
private final String label;
private List<Point> controlPoints;
public BlockConnection(Block src, Block dst, String label) {
this.sourceBlock = src;
this.destinationBlock = dst;
this.label = label;
}
public Color getColor() {
return Color.BLUE;
}
public ConnectionStyle getStyle() {
return ConnectionStyle.BOLD;
}
@Override
public String getToolTipText() {
StringBuilder builder = new StringBuilder();
builder.append("B").append(sourceBlock.getInputBlock().getName())
.append(" → B").append(destinationBlock.getInputBlock().getName());
if (label != null) {
builder.append(": ").append(label);
}
return builder.toString();
}
@Override
public String toString() {
return "BlockConnection('" + label + "', " + getFromCluster() + " to " + getToCluster() + ")";
}
@Override
public Port getFrom() {
return null;
}
@Override
public Block getFromCluster() {
return sourceBlock;
}
@Override
public Port getTo() {
return null;
}
@Override
public Block getToCluster() {
return destinationBlock;
}
@Override
public boolean isVIP() {
return true;
}
@Override
public List<Point> getControlPoints() {
return controlPoints;
}
@Override
public void setControlPoints(List<Point> list) {
controlPoints = list;
}
@Override
public boolean isAlwaysVisible() {
return true;
}
@Override
public boolean hasSlots() {
return false;
}
}

@ -0,0 +1,30 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package com.sun.hotspot.igv.graph;
import java.util.List;
public interface BlockSelector {
List<Block> selected(Diagram d);
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@ -23,143 +23,26 @@
*/
package com.sun.hotspot.igv.graph;
import com.sun.hotspot.igv.data.Source;
import com.sun.hotspot.igv.layout.Link;
import com.sun.hotspot.igv.layout.Port;
import java.awt.Color;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author Thomas Wuerthinger
*/
public class Connection implements Source.Provider, Link {
@Override
public boolean isVIP() {
return style == ConnectionStyle.BOLD;
}
public interface Connection extends Link {
public enum ConnectionStyle {
NORMAL,
DASHED,
BOLD,
INVISIBLE
}
private InputSlot inputSlot;
private OutputSlot outputSlot;
private Source source;
private Color color;
private ConnectionStyle style;
private List<Point> controlPoints;
private String label;
private String type;
protected Connection(InputSlot inputSlot, OutputSlot outputSlot, String label, String type) {
this.inputSlot = inputSlot;
this.outputSlot = outputSlot;
this.label = label;
this.type = type;
this.inputSlot.connections.add(this);
this.outputSlot.connections.add(this);
controlPoints = new ArrayList<>();
Figure sourceFigure = this.outputSlot.getFigure();
Figure destFigure = this.inputSlot.getFigure();
sourceFigure.addSuccessor(destFigure);
destFigure.addPredecessor(sourceFigure);
source = new Source();
public ConnectionStyle getStyle();
this.color = Color.BLACK;
this.style = ConnectionStyle.NORMAL;
}
public Color getColor();
public InputSlot getInputSlot() {
return inputSlot;
}
public String getToolTipText();
public OutputSlot getOutputSlot() {
return outputSlot;
}
public boolean isAlwaysVisible();
public Color getColor() {
return color;
}
public boolean hasSlots();
public ConnectionStyle getStyle() {
return style;
}
public void setColor(Color c) {
color = c;
}
public void setStyle(ConnectionStyle s) {
style = s;
}
@Override
public Source getSource() {
return source;
}
public String getLabel() {
return label;
}
public String getType() {
return type;
}
public void remove() {
inputSlot.getFigure().removePredecessor(outputSlot.getFigure());
inputSlot.connections.remove(this);
outputSlot.getFigure().removeSuccessor(inputSlot.getFigure());
outputSlot.connections.remove(this);
}
public String getToolTipText() {
StringBuilder builder = new StringBuilder();
if (label != null) {
builder.append(label).append(": ");
}
if (type != null) {
builder.append(type).append(" ");
}
// Resolve strings lazily every time the tooltip is shown, instead of
// eagerly as for node labels, for efficiency.
String shortNodeText = getInputSlot().getFigure().getDiagram().getShortNodeText();
builder.append(getOutputSlot().getFigure().getProperties().resolveString(shortNodeText));
builder.append("");
builder.append(getInputSlot().getFigure().getProperties().resolveString(shortNodeText));
return builder.toString();
}
@Override
public String toString() {
return "Connection('" + label + "', " + getFrom().getVertex() + " to " + getTo().getVertex() + ")";
}
@Override
public Port getFrom() {
return outputSlot;
}
@Override
public Port getTo() {
return inputSlot;
}
@Override
public List<Point> getControlPoints() {
return controlPoints;
}
@Override
public void setControlPoints(List<Point> list) {
controlPoints = list;
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -24,12 +24,14 @@
package com.sun.hotspot.igv.graph;
import com.sun.hotspot.igv.data.InputBlock;
import com.sun.hotspot.igv.data.InputBlockEdge;
import com.sun.hotspot.igv.data.InputEdge;
import com.sun.hotspot.igv.data.InputGraph;
import com.sun.hotspot.igv.data.InputNode;
import com.sun.hotspot.igv.data.Properties;
import com.sun.hotspot.igv.data.Properties.StringPropertyMatcher;
import java.awt.Font;
import java.awt.Color;
import java.util.*;
/**
@ -44,9 +46,14 @@ public class Diagram {
private int curId;
private String nodeText;
private String shortNodeText;
private String tinyNodeText;
private final Font font;
private final Font slotFont;
private final Font boldFont;
// Whether widgets derived from this diagram should be adapted for the
// control-flow graph view.
private boolean cfg;
private final Set<BlockConnection> blockConnections;
public Font getFont() {
return font;
@ -60,7 +67,16 @@ public class Diagram {
return boldFont;
}
private Diagram() {
public boolean isCFG() {
return cfg;
}
public void setCFG(boolean cfg) {
this.cfg = cfg;
}
private Diagram(InputGraph graph, String nodeText, String shortNodeText,
String tinyNodeText) {
figures = new ArrayList<>();
blocks = new LinkedHashMap<>(8);
this.nodeText = "";
@ -68,6 +84,12 @@ public class Diagram {
this.font = new Font("Arial", Font.PLAIN, 12);
this.slotFont = new Font("Arial", Font.PLAIN, 10);
this.boldFont = this.font.deriveFont(Font.BOLD);
this.cfg = false;
this.blockConnections = new HashSet<>();
this.graph = graph;
this.nodeText = nodeText;
this.shortNodeText = shortNodeText;
this.tinyNodeText = tinyNodeText;
}
public Block getBlock(InputBlock b) {
@ -75,6 +97,10 @@ public class Diagram {
return blocks.get(b);
}
public boolean hasBlock(InputBlock b) {
return blocks.containsKey(b);
}
public String getNodeText() {
return nodeText;
}
@ -83,6 +109,10 @@ public class Diagram {
return shortNodeText;
}
public String getTinyNodeText() {
return tinyNodeText;
}
public void updateBlocks() {
blocks.clear();
for (InputBlock b : graph.getBlocks()) {
@ -91,18 +121,10 @@ public class Diagram {
}
}
public Diagram getNext() {
return Diagram.createDiagram(graph.getNext(), nodeText, shortNodeText);
}
public Collection<Block> getBlocks() {
return Collections.unmodifiableCollection(blocks.values());
}
public Diagram getPrev() {
return Diagram.createDiagram(graph.getPrev(), nodeText, shortNodeText);
}
public List<Figure> getFigures() {
return Collections.unmodifiableList(figures);
}
@ -114,10 +136,10 @@ public class Diagram {
return f;
}
public Connection createConnection(InputSlot inputSlot, OutputSlot outputSlot, String label, String type) {
public FigureConnection createConnection(InputSlot inputSlot, OutputSlot outputSlot, String label) {
assert inputSlot.getFigure().getDiagram() == this;
assert outputSlot.getFigure().getDiagram() == this;
return new Connection(inputSlot, outputSlot, label, type);
return new FigureConnection(inputSlot, outputSlot, label);
}
public Map<InputNode, Set<Figure>> calcSourceToFigureRelation() {
@ -137,16 +159,13 @@ public class Diagram {
}
public static Diagram createDiagram(InputGraph graph, String nodeText,
String shortNodeText) {
String shortNodeText,
String tinyNodeText) {
if (graph == null) {
return null;
}
Diagram d = new Diagram();
d.graph = graph;
d.nodeText = nodeText;
d.shortNodeText = shortNodeText;
Diagram d = new Diagram(graph, nodeText, shortNodeText, tinyNodeText);
d.updateBlocks();
Collection<InputNode> nodes = graph.getNodes();
@ -156,6 +175,7 @@ public class Diagram {
f.getSource().addSourceNode(n);
f.getProperties().add(n.getProperties());
f.setSubgraphs(n.getSubgraphs());
f.setBlock(graph.getBlock(n));
figureHash.put(n.getId(), f);
}
@ -181,7 +201,7 @@ public class Diagram {
}
InputSlot inputSlot = toFigure.getInputSlots().get(toIndex);
Connection c = d.createConnection(inputSlot, outputSlot, e.getLabel(), e.getType());
FigureConnection c = d.createConnection(inputSlot, outputSlot, e.getLabel());
if (e.getState() == InputEdge.State.NEW) {
c.setStyle(Connection.ConnectionStyle.BOLD);
@ -190,10 +210,30 @@ public class Diagram {
}
}
for (InputBlockEdge e : graph.getBlockEdges()) {
Block p = d.getBlock(e.getFrom());
Block s = d.getBlock(e.getTo());
d.blockConnections.add(new BlockConnection(p, s, e.getLabel()));
}
return d;
}
public void removeAllBlocks(Set<Block> blocksToRemove) {
Set<Figure> figuresToRemove = new HashSet<>();
for (Block b : blocksToRemove) {
for (Figure f : getFigures()) {
if (f.getBlock() == b.getInputBlock()) {
figuresToRemove.add(f);
}
}
}
removeAllFigures(figuresToRemove);
for (Block b : blocksToRemove) {
blocks.remove(b.getInputBlock());
}
}
public void removeAllFigures(Set<Figure> figuresToRemove) {
for (Figure f : figuresToRemove) {
freeFigure(f);
@ -228,7 +268,6 @@ public class Diagram {
}
public void removeFigure(Figure succ) {
assert this.figures.contains(succ);
freeFigure(succ);
this.figures.remove(succ);
@ -242,16 +281,24 @@ public class Diagram {
return graph;
}
public Set<Connection> getConnections() {
Set<Connection> connections = new HashSet<>();
public Set<FigureConnection> getConnections() {
Set<FigureConnection> connections = new HashSet<>();
for (Figure f : figures) {
for (InputSlot s : f.getInputSlots()) {
connections.addAll(s.getConnections());
}
}
return connections;
}
public Set<BlockConnection> getBlockConnections() {
Set<BlockConnection> connections = new HashSet<>();
for (BlockConnection bc : blockConnections) {
if (blocks.containsKey(bc.getFromCluster().getInputBlock()) &&
blocks.containsKey(bc.getToCluster().getInputBlock())) {
connections.add(bc);
}
}
return connections;
}
@ -278,7 +325,7 @@ public class Diagram {
System.out.println("Diagram statistics");
List<Figure> tmpFigures = getFigures();
Set<Connection> connections = getConnections();
Set<FigureConnection> connections = getConnections();
System.out.println("Number of figures: " + tmpFigures.size());
System.out.println("Number of connections: " + connections.size());

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -31,18 +31,18 @@ import com.sun.hotspot.igv.data.Source;
import com.sun.hotspot.igv.layout.Cluster;
import com.sun.hotspot.igv.layout.Vertex;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.List;
import java.util.*;
public class Figure extends Properties.Entity implements Source.Provider, Vertex {
public static final int INSET = 8;
public static int SLOT_WIDTH = 10;
public static final int SLOT_WIDTH = 10;
public static final int OVERLAPPING = 6;
public static final int SLOT_START = 4;
public static final int SLOT_OFFSET = 8;
public static final boolean VERTICAL_LAYOUT = true;
public static final int TOP_CFG_HEIGHT = 7;
public static final int BOTTOM_CFG_HEIGHT = 6;
protected List<InputSlot> inputSlots;
protected List<OutputSlot> outputSlots;
private Source source;
@ -57,19 +57,33 @@ public class Figure extends Properties.Entity implements Source.Provider, Vertex
private String[] lines;
private int heightCash = -1;
private int widthCash = -1;
private InputBlock block;
private final FontMetrics metrics;
public int getHeight() {
if (heightCash == -1) {
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.setFont(diagram.getFont().deriveFont(Font.BOLD));
FontMetrics metrics = g.getFontMetrics();
String nodeText = diagram.getNodeText();
heightCash = nodeText.split("\n").length * metrics.getHeight() + INSET;
updateHeight();
}
return heightCash;
}
private void updateHeight() {
String nodeText = diagram.getNodeText();
int lines = nodeText.split("\n").length;
if (hasInputList() && lines > 1) {
lines++;
}
heightCash = lines * metrics.getHeight() + INSET;
if (diagram.isCFG()) {
if (hasNamedInputSlot()) {
heightCash += TOP_CFG_HEIGHT;
}
if (hasNamedOutputSlot()) {
heightCash += BOTTOM_CFG_HEIGHT;
}
}
}
public static <T> List<T> getAllBefore(List<T> inputList, T tIn) {
List<T> result = new ArrayList<>();
for(T t : inputList) {
@ -91,11 +105,17 @@ public class Figure extends Properties.Entity implements Source.Provider, Vertex
public int getWidth() {
if (widthCash == -1) {
updateWidth();
}
return widthCash;
}
public void setWidth(int width) {
widthCash = width;
}
private void updateWidth() {
int max = 0;
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.setFont(diagram.getFont().deriveFont(Font.BOLD));
FontMetrics metrics = g.getFontMetrics();
for (String s : getLines()) {
int cur = metrics.stringWidth(s);
if (cur > max) {
@ -105,8 +125,6 @@ public class Figure extends Properties.Entity implements Source.Provider, Vertex
widthCash = max + INSET;
widthCash = Math.max(widthCash, Figure.getSlotsWidth(inputSlots));
widthCash = Math.max(widthCash, Figure.getSlotsWidth(outputSlots));
}
return widthCash;
}
protected Figure(Diagram diagram, int id) {
@ -121,6 +139,8 @@ public class Figure extends Properties.Entity implements Source.Provider, Vertex
this.position = new Point(0, 0);
this.color = Color.WHITE;
Canvas canvas = new Canvas();
metrics = canvas.getFontMetrics(diagram.getFont().deriveFont(Font.BOLD));
}
public int getId() {
@ -135,6 +155,18 @@ public class Figure extends Properties.Entity implements Source.Provider, Vertex
return color;
}
public boolean hasInputList() {
return diagram.isCFG() && !getPredecessors().isEmpty();
}
public void setBlock(InputBlock block) {
this.block = block;
}
public InputBlock getBlock() {
return block;
}
public List<Figure> getPredecessors() {
return Collections.unmodifiableList(predecessors);
}
@ -221,8 +253,8 @@ public class Figure extends Properties.Entity implements Source.Provider, Vertex
assert inputSlots.contains(s) || outputSlots.contains(s);
List<Connection> connections = new ArrayList<>(s.getConnections());
for (Connection c : connections) {
List<FigureConnection> connections = new ArrayList<>(s.getConnections());
for (FigureConnection c : connections) {
c.remove();
}
@ -261,6 +293,24 @@ public class Figure extends Properties.Entity implements Source.Provider, Vertex
return Collections.unmodifiableList(outputSlots);
}
public boolean hasNamedInputSlot() {
for (InputSlot is : getInputSlots()) {
if (is.hasSourceNodes() && is.shouldShowName()) {
return true;
}
}
return false;
}
public boolean hasNamedOutputSlot() {
for (OutputSlot os : getOutputSlots()) {
if (os.hasSourceNodes() && os.shouldShowName()) {
return true;
}
}
return false;
}
void removeInputSlot(InputSlot s) {
s.removeAllConnections();
inputSlots.remove(s);
@ -274,41 +324,52 @@ public class Figure extends Properties.Entity implements Source.Provider, Vertex
public String[] getLines() {
if (lines == null) {
updateLines();
// Set the "label" property of each input node, so that by default
// search is done on the node label (without line breaks). See also
// class NodeQuickSearch in the View module.
for (InputNode n : getSource().getSourceNodes()) {
String label = n.getProperties().resolveString(diagram.getNodeText());
n.getProperties().setProperty("label", label.replaceAll("\\R", " "));
}
}
return lines;
}
public void updateLines() {
String[] strings = diagram.getNodeText().split("\n");
String[] result = new String[strings.length];
List<String> result = new ArrayList<>(strings.length + 1);
for (int i = 0; i < strings.length; i++) {
result[i] = getProperties().resolveString(strings[i]);
result.add(getProperties().resolveString(strings[i]));
}
lines = result;
if (hasInputList()) {
String inputList = "";
List<String> inputs = new ArrayList<String>(getPredecessors().size());
for (Figure p : getPredecessors()) {
inputs.add(p.getProperties().resolveString(diagram.getTinyNodeText()));
}
inputList += String.join(" ", inputs);
if (result.size() == 1) {
// Single-line node, append input list to line.
result.set(0, result.get(0) + inputList);
} else {
// Multi-line node, add yet another line for input list.
result.add(inputList);
}
}
lines = result.toArray(new String[0]);
// Set the "label" property of each input node, so that by default
// search is done on the node label (without line breaks). See also
// class NodeQuickSearch in the View module.
for (InputNode n : getSource().getSourceNodes()) {
String label = n.getProperties().resolveString(diagram.getNodeText());
n.getProperties().setProperty("label", label.replaceAll("\\R", " "));
}
// Update figure dimensions, as these are affected by the node text.
updateWidth();
updateHeight();
}
@Override
public Dimension getSize() {
if (VERTICAL_LAYOUT) {
int width = Math.max(getWidth(), Figure.SLOT_WIDTH * (Math.max(inputSlots.size(), outputSlots.size()) + 1));
int height = getHeight() + 2 * Figure.SLOT_WIDTH - 2 * Figure.OVERLAPPING;
return new Dimension(width, height);
} else {
int width = getWidth() + 2 * Figure.SLOT_WIDTH - 2*Figure.OVERLAPPING;
int height = Figure.SLOT_WIDTH * (Math.max(inputSlots.size(), outputSlots.size()) + 1);
return new Dimension(width, height);
}
int width = Math.max(getWidth(), Figure.SLOT_WIDTH * (Math.max(inputSlots.size(), outputSlots.size()) + 1));
int height = getHeight() + (diagram.isCFG() ? 0 : 2 * Figure.SLOT_WIDTH - 2 * Figure.OVERLAPPING);
return new Dimension(width, height);
}
@Override
@ -316,12 +377,20 @@ public class Figure extends Properties.Entity implements Source.Provider, Vertex
return idString;
}
public InputNode getFirstSourceNode() {
return getSource().getSourceNodes().get(0);
}
public static int getVerticalOffset() {
return Figure.SLOT_WIDTH - Figure.OVERLAPPING;
}
public Cluster getCluster() {
if (getSource().getSourceNodes().size() == 0) {
assert false : "Should never reach here, every figure must have at least one source node!";
return null;
} else {
final InputBlock inputBlock = diagram.getGraph().getBlock(getSource().getSourceNodes().get(0));
final InputBlock inputBlock = diagram.getGraph().getBlock(getFirstSourceNode());
assert inputBlock != null;
Cluster result = diagram.getBlock(inputBlock);
assert result != null;
@ -333,8 +402,8 @@ public class Figure extends Properties.Entity implements Source.Provider, Vertex
public boolean isRoot() {
List<InputNode> sourceNodes = source.getSourceNodes();
if (sourceNodes.size() > 0 && sourceNodes.get(0).getProperties().get("name") != null) {
return source.getSourceNodes().get(0).getProperties().get("name").equals("Root");
if (sourceNodes.size() > 0 && getFirstSourceNode().getProperties().get("name") != null) {
return getFirstSourceNode().getProperties().get("name").equals("Root");
} else {
return false;
}

@ -0,0 +1,162 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package com.sun.hotspot.igv.graph;
import com.sun.hotspot.igv.layout.Port;
import com.sun.hotspot.igv.layout.Cluster;
import java.awt.Color;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author Thomas Wuerthinger
*/
public class FigureConnection implements Connection {
private final InputSlot inputSlot;
private final OutputSlot outputSlot;
private Color color;
private ConnectionStyle style;
private List<Point> controlPoints;
private String label;
protected FigureConnection(InputSlot inputSlot, OutputSlot outputSlot, String label) {
this.inputSlot = inputSlot;
this.outputSlot = outputSlot;
this.label = label;
this.inputSlot.connections.add(this);
this.outputSlot.connections.add(this);
controlPoints = new ArrayList<>();
Figure sourceFigure = this.outputSlot.getFigure();
Figure destFigure = this.inputSlot.getFigure();
sourceFigure.addSuccessor(destFigure);
destFigure.addPredecessor(sourceFigure);
this.color = Color.BLACK;
this.style = ConnectionStyle.NORMAL;
}
public InputSlot getInputSlot() {
return inputSlot;
}
public OutputSlot getOutputSlot() {
return outputSlot;
}
public Color getColor() {
return color;
}
public ConnectionStyle getStyle() {
return style;
}
public void setColor(Color c) {
color = c;
}
public void setStyle(ConnectionStyle s) {
style = s;
}
public String getLabel() {
return label;
}
public void remove() {
inputSlot.getFigure().removePredecessor(outputSlot.getFigure());
inputSlot.connections.remove(this);
outputSlot.getFigure().removeSuccessor(inputSlot.getFigure());
outputSlot.connections.remove(this);
}
public String getToolTipText() {
StringBuilder builder = new StringBuilder();
if (label != null) {
builder.append(label).append(": ");
}
// Resolve strings lazily every time the tooltip is shown, instead of
// eagerly as for node labels, for efficiency.
String shortNodeText = getInputSlot().getFigure().getDiagram().getShortNodeText();
builder.append(getOutputSlot().getFigure().getProperties().resolveString(shortNodeText));
builder.append("");
builder.append(getInputSlot().getFigure().getProperties().resolveString(shortNodeText));
return builder.toString();
}
@Override
public String toString() {
return "FigureConnection('" + label + "', " + getFrom().getVertex() + " to " + getTo().getVertex() + ")";
}
@Override
public Port getFrom() {
return outputSlot;
}
@Override
public Cluster getFromCluster() {
return getFrom().getVertex().getCluster();
}
@Override
public Port getTo() {
return inputSlot;
}
@Override
public Cluster getToCluster() {
return getTo().getVertex().getCluster();
}
@Override
public boolean isVIP() {
return style == ConnectionStyle.BOLD;
}
@Override
public List<Point> getControlPoints() {
return controlPoints;
}
@Override
public void setControlPoints(List<Point> list) {
controlPoints = list;
}
@Override
public boolean isAlwaysVisible() {
return false;
}
@Override
public boolean hasSlots() {
return true;
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -47,7 +47,7 @@ public abstract class Slot implements Port, Source.Provider, Properties.Provider
private int wantedIndex;
private Source source;
protected List<Connection> connections;
protected List<FigureConnection> connections;
private InputNode associatedNode;
private Color color;
private String text;
@ -67,7 +67,7 @@ public abstract class Slot implements Port, Source.Provider, Properties.Provider
@Override
public Properties getProperties() {
Properties p = new Properties();
if (source.getSourceNodes().size() > 0) {
if (hasSourceNodes()) {
for (InputNode n : source.getSourceNodes()) {
p.add(n.getProperties());
}
@ -158,6 +158,10 @@ public abstract class Slot implements Port, Source.Provider, Properties.Provider
return getShortName() != null && getShortName().length() > 0;
}
public boolean hasSourceNodes() {
return !getSource().getSourceNodes().isEmpty();
}
public void setText(String s) {
if (s == null) {
s = "";
@ -178,13 +182,13 @@ public abstract class Slot implements Port, Source.Provider, Properties.Provider
color = c;
}
public List<Connection> getConnections() {
public List<FigureConnection> getConnections() {
return Collections.unmodifiableList(connections);
}
public void removeAllConnections() {
List<Connection> connectionsCopy = new ArrayList<>(this.connections);
for (Connection c : connectionsCopy) {
List<FigureConnection> connectionsCopy = new ArrayList<>(this.connections);
for (FigureConnection c : connectionsCopy) {
c.remove();
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -25,6 +25,7 @@ package com.sun.hotspot.igv.hierarchicallayout;
import com.sun.hotspot.igv.layout.Link;
import com.sun.hotspot.igv.layout.Port;
import com.sun.hotspot.igv.layout.Cluster;
import java.awt.Point;
import java.util.List;
@ -53,6 +54,14 @@ public class ClusterEdge implements Link {
return from.getInputSlot();
}
public Cluster getFromCluster() {
return from.getCluster();
}
public Cluster getToCluster() {
return to.getCluster();
}
public void setControlPoints(List<Point> p) {
this.points = p;
}
@ -64,4 +73,9 @@ public class ClusterEdge implements Link {
public boolean isVIP() {
return false;
}
@Override
public String toString() {
return from + "->" + to;
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -25,6 +25,7 @@ package com.sun.hotspot.igv.hierarchicallayout;
import com.sun.hotspot.igv.layout.Link;
import com.sun.hotspot.igv.layout.Port;
import com.sun.hotspot.igv.layout.Cluster;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
@ -66,6 +67,14 @@ public class ClusterIngoingConnection implements Link {
return outputSlot;
}
public Cluster getFromCluster() {
return null;
}
public Cluster getToCluster() {
return null;
}
public void setControlPoints(List<Point> p) {
this.controlPoints = p;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -87,7 +87,7 @@ public class ClusterInputSlotNode implements Vertex {
public Point getRelativePosition() {
Point p = new Point(thisNode.getPosition());
p.x += ClusterNode.BORDER;
p.x += blockNode.getBorder();
p.y = 0;
return p;
}
@ -142,4 +142,5 @@ public class ClusterInputSlotNode implements Vertex {
public int compareTo(Vertex o) {
return toString().compareTo(o.toString());
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -51,14 +51,34 @@ public class ClusterNode implements Vertex {
private boolean dirty;
private boolean root;
private String name;
public static final int BORDER = 20;
private final int border;
private final Dimension nodeOffset;
private final int headerVerticalSpace;
private final Dimension emptySize;
public ClusterNode(Cluster cluster, String name) {
public ClusterNode(Cluster cluster, String name, int border,
Dimension nodeOffset, int headerVerticalSpace,
Dimension emptySize) {
this.subNodes = new HashSet<Vertex>();
this.subEdges = new HashSet<Link>();
this.cluster = cluster;
position = new Point(0, 0);
this.name = name;
this.border = border;
this.nodeOffset = nodeOffset;
this.headerVerticalSpace = headerVerticalSpace;
this.emptySize = emptySize;
if (emptySize.width > 0 || emptySize.height > 0) {
updateSize();
}
}
public ClusterNode(Cluster cluster, String name) {
this(cluster, name, 20, new Dimension(0, 0), 0, new Dimension(0, 0));
}
public String getName() {
return name;
}
public void addSubNode(Vertex v) {
@ -88,6 +108,11 @@ public class ClusterNode implements Vertex {
public Vertex getVertex() {
return widget;
}
@Override
public String toString() {
return "ClusterInput(" + name + ")";
}
};
outputSlot = new Port() {
@ -99,13 +124,19 @@ public class ClusterNode implements Vertex {
public Vertex getVertex() {
return widget;
}
@Override
public String toString() {
return "ClusterOutput(" + name + ")";
}
};
}
private void calculateSize() {
if (subNodes.size() == 0) {
size = new Dimension(0, 0);
if (subNodes.isEmpty()) {
size = emptySize;
return;
}
int minX = Integer.MAX_VALUE;
@ -134,11 +165,12 @@ public class ClusterNode implements Vertex {
}
}
size = new Dimension(maxX - minX, maxY - minY);
size = new Dimension(maxX - minX, maxY - minY + headerVerticalSpace);
// Normalize coordinates
for (Vertex n : subNodes) {
n.setPosition(new Point(n.getPosition().x - minX, n.getPosition().y - minY));
n.setPosition(new Point(n.getPosition().x - minX + nodeOffset.width,
n.getPosition().y - minY + nodeOffset.height + headerVerticalSpace));
}
for (Link l : subEdges) {
@ -151,8 +183,8 @@ public class ClusterNode implements Vertex {
}
size.width += 2 * BORDER;
size.height += 2 * BORDER;
size.width += 2 * border;
size.height += 2 * border;
}
public Port getInputSlot() {
@ -177,7 +209,7 @@ public class ClusterNode implements Vertex {
this.position = pos;
for (Vertex n : subNodes) {
Point cur = new Point(n.getPosition());
cur.translate(pos.x + BORDER, pos.y + BORDER);
cur.translate(pos.x + border, pos.y + border);
n.setPosition(cur);
}
@ -187,7 +219,7 @@ public class ClusterNode implements Vertex {
for (Point p : arr) {
if (p != null) {
Point p2 = new Point(p);
p2.translate(pos.x + BORDER, pos.y + BORDER);
p2.translate(pos.x + border, pos.y + border);
newArr.add(p2);
} else {
newArr.add(null);
@ -218,6 +250,10 @@ public class ClusterNode implements Vertex {
return root;
}
public int getBorder() {
return border;
}
public int compareTo(Vertex o) {
return toString().compareTo(o.toString());
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -25,6 +25,7 @@ package com.sun.hotspot.igv.hierarchicallayout;
import com.sun.hotspot.igv.layout.Link;
import com.sun.hotspot.igv.layout.Port;
import com.sun.hotspot.igv.layout.Cluster;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
@ -58,6 +59,14 @@ public class ClusterOutgoingConnection implements Link {
return outputSlot;
}
public Cluster getFromCluster() {
return null;
}
public Cluster getToCluster() {
return null;
}
public void setControlPoints(List<Point> p) {
this.intermediatePoints = p;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -87,7 +87,7 @@ public class ClusterOutputSlotNode implements Vertex {
public Point getRelativePosition() {
Point p = new Point(thisNode.getPosition());
p.x += ClusterNode.BORDER;
p.x += blockNode.getBorder();
p.y = 0;//thisBlockNode.getSize().height;
return p;
}
@ -142,4 +142,5 @@ public class ClusterOutputSlotNode implements Vertex {
public int compareTo(Vertex o) {
return toString().compareTo(o.toString());
}
}

@ -0,0 +1,155 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package com.sun.hotspot.igv.hierarchicallayout;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Canvas;
import java.awt.Font;
import java.awt.FontMetrics;
import java.util.*;
import com.sun.hotspot.igv.layout.Cluster;
import com.sun.hotspot.igv.layout.LayoutGraph;
import com.sun.hotspot.igv.layout.LayoutManager;
import com.sun.hotspot.igv.layout.Link;
import com.sun.hotspot.igv.layout.Vertex;
public class HierarchicalCFGLayoutManager implements LayoutManager {
private static final int BLOCK_BORDER = 5;
private FontMetrics fontMetrics;
// Lays out nodes within a single cluster (basic block).
private LayoutManager subManager;
// Lays out clusters in the CFG.
private LayoutManager manager;
private Set<Cluster> clusters;
public HierarchicalCFGLayoutManager() {
// Anticipate block label sizes to dimension blocks appropriately.
Canvas canvas = new Canvas();
Font font = new Font("Arial", Font.BOLD, 14);
fontMetrics = canvas.getFontMetrics(font);
}
public void setSubManager(LayoutManager manager) {
this.subManager = manager;
}
public void setManager(LayoutManager manager) {
this.manager = manager;
}
public void setClusters(Set<Cluster> clusters) {
this.clusters = clusters;
}
public void doLayout(LayoutGraph graph, Set<? extends Link> importantLinks) {
doLayout(graph);
}
public void doLayout(LayoutGraph graph) {
// Create cluster-level nodes and edges.
Map<Cluster, ClusterNode> clusterNode = createClusterNodes(graph);
Set<ClusterEdge> clusterEdges = createClusterEdges(clusterNode);
markRootClusters(clusterEdges);
// Compute layout for each cluster.
for (Cluster c : clusters) {
ClusterNode n = clusterNode.get(c);
subManager.doLayout(new LayoutGraph(n.getSubEdges(), n.getSubNodes()), new HashSet<Link>());
n.updateSize();
}
// Compute inter-cluster layout.
manager.doLayout(new LayoutGraph(clusterEdges, new HashSet<>(clusterNode.values())),
new HashSet<Link>());
// Write back results.
writeBackClusterBounds(clusterNode);
writeBackClusterEdgePoints(graph, clusterEdges);
}
private Map<Cluster, ClusterNode> createClusterNodes(LayoutGraph graph) {
Map<Cluster, ClusterNode> clusterNode = new HashMap<>();
for (Cluster c : clusters) {
String blockLabel = "B" + c;
Dimension emptySize = new Dimension(fontMetrics.stringWidth(blockLabel) + BLOCK_BORDER * 2,
fontMetrics.getHeight() + BLOCK_BORDER);
ClusterNode cn = new ClusterNode(c, c.toString(), BLOCK_BORDER, c.getNodeOffset(),
fontMetrics.getHeight(), emptySize);
clusterNode.put(c, cn);
}
for (Vertex v : graph.getVertices()) {
Cluster c = v.getCluster();
assert c != null : "Cluster of vertex " + v + " is null!";
clusterNode.get(c).addSubNode(v);
}
return clusterNode;
}
private Set<ClusterEdge> createClusterEdges(Map<Cluster, ClusterNode> clusterNode) {
Set<ClusterEdge> clusterEdges = new HashSet<>();
for (Cluster c : clusters) {
ClusterNode start = clusterNode.get(c);
for (Cluster succ : c.getSuccessors()) {
ClusterNode end = clusterNode.get(succ);
if (end != null) {
ClusterEdge e = new ClusterEdge(start, end);
clusterEdges.add(e);
}
}
}
return clusterEdges;
}
private void markRootClusters(Set<ClusterEdge> clusterEdges) {
Set<Vertex> roots = new LayoutGraph(clusterEdges).findRootVertices();
for (Vertex v : roots) {
assert v instanceof ClusterNode;
((ClusterNode) v).setRoot(true);
}
}
private void writeBackClusterBounds(Map<Cluster, ClusterNode> clusterNode) {
for (Cluster c : clusters) {
ClusterNode n = clusterNode.get(c);
c.setBounds(new Rectangle(n.getPosition(), n.getSize()));
}
}
private void writeBackClusterEdgePoints(LayoutGraph graph, Set<ClusterEdge> clusterEdges) {
// Map from "primitive" cluster edges to their input links.
Map<AbstractMap.SimpleEntry<Cluster, Cluster>, Link> inputLink = new HashMap<>();
for (Link l : graph.getLinks()) {
inputLink.put(new AbstractMap.SimpleEntry<Cluster, Cluster>(l.getFromCluster(), l.getToCluster()), l);
}
for (ClusterEdge ce : clusterEdges) {
assert (ce.getControlPoints() != null);
Link l = inputLink.get(new AbstractMap.SimpleEntry<Cluster, Cluster>(ce.getFromCluster(), ce.getToCluster()));
l.setControlPoints(ce.getControlPoints());
}
}
}

@ -245,7 +245,4 @@ public class HierarchicalClusterLayoutManager implements LayoutManager {
}
}
}
public void doRouting(LayoutGraph graph) {
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -63,8 +63,10 @@ public class HierarchicalLayoutManager implements LayoutManager {
private int layerOffset;
private int maxLayerLength;
private int minLayerDifference;
private boolean layoutSelfEdges;
// Algorithm global datastructures
private Set<Link> reversedLinks;
private Set<LayoutEdge> selfEdges;
private List<LayoutNode> nodes;
private HashMap<Vertex, LayoutNode> vertexToLayoutNode;
private HashMap<Link, List<Point>> reversedLinkStartPoints;
@ -108,10 +110,17 @@ public class HierarchicalLayoutManager implements LayoutManager {
public LayoutNode from;
public LayoutNode to;
// Horizontal distance relative to start of 'from'.
public int relativeFrom;
// Horizontal distance relative to start of 'to'.
public int relativeTo;
public Link link;
public boolean vip;
@Override
public String toString() {
return "Edge " + from + ", " + to;
}
}
private abstract class AlgorithmPart {
@ -162,9 +171,18 @@ public class HierarchicalLayoutManager implements LayoutManager {
this.layerOffset = LAYER_OFFSET;
this.maxLayerLength = MAX_LAYER_LENGTH;
this.minLayerDifference = MIN_LAYER_DIFFERENCE;
this.layoutSelfEdges = false;
this.linksToFollow = new HashSet<>();
}
public void setXOffset(int xOffset) {
this.xOffset = xOffset;
}
public void setLayerOffset(int layerOffset) {
this.layerOffset = layerOffset;
}
public int getMaxLayerLength() {
return maxLayerLength;
}
@ -177,6 +195,25 @@ public class HierarchicalLayoutManager implements LayoutManager {
minLayerDifference = v;
}
public void setLayoutSelfEdges(boolean layoutSelfEdges) {
this.layoutSelfEdges = layoutSelfEdges;
}
// Remove self-edges, possibly saving them into the selfEdges set.
private void removeSelfEdges(boolean save) {
for (LayoutNode node : nodes) {
for (LayoutEdge e : new ArrayList<>(node.succs)) {
if (e.to == node) {
if (save) {
selfEdges.add(e);
}
node.succs.remove(e);
node.preds.remove(e);
}
}
}
}
@Override
public void doLayout(LayoutGraph graph) {
doLayout(graph, new HashSet<Link>());
@ -191,6 +228,7 @@ public class HierarchicalLayoutManager implements LayoutManager {
vertexToLayoutNode = new HashMap<>();
reversedLinks = new HashSet<>();
selfEdges = new HashSet<>();
reversedLinkStartPoints = new HashMap<>();
reversedLinkEndPoints = new HashMap<>();
bottomEdgeHash = new HashMap<>();
@ -202,6 +240,11 @@ public class HierarchicalLayoutManager implements LayoutManager {
// Step 1: Build up data structure
new BuildDatastructure().start();
if (!layoutSelfEdges) {
// Remove self-edges from the beginning.
removeSelfEdges(false);
}
// #############################################################
// STEP 2: Reverse edges, handle backedges
new ReverseEdges().start();
@ -220,6 +263,9 @@ public class HierarchicalLayoutManager implements LayoutManager {
}
}
// Hide self-edges from the layout algorithm and save them for later.
removeSelfEdges(true);
// #############################################################
// STEP 3: Assign layers
new AssignLayers().start();
@ -240,6 +286,12 @@ public class HierarchicalLayoutManager implements LayoutManager {
// STEP 6: Assign Y coordinates
new AssignYCoordinates().start();
// Put saved self-edges back so that they are assigned points.
for (LayoutEdge e : selfEdges) {
e.from.succs.add(e);
e.to.preds.add(e);
}
// #############################################################
// STEP 8: Write back to interface
new WriteResult().start();
@ -322,6 +374,11 @@ public class HierarchicalLayoutManager implements LayoutManager {
} else {
if (reversedLinks.contains(e.link)) {
Collections.reverse(points);
if (selfEdges.contains(e)) {
// For self edges, it is enough with the
// start and end points computed by ReverseEdges.
points.clear();
}
}
if (reversedLinkStartPoints.containsKey(e.link)) {
for (Point p1 : reversedLinkStartPoints.get(e.link)) {
@ -351,7 +408,11 @@ public class HierarchicalLayoutManager implements LayoutManager {
Point p = new Point(e.from.x + e.relativeFrom, e.from.y + e.from.height - e.from.bottomYOffset + e.link.getFrom().getRelativePosition().y);
points.add(p);
if (e.from.outOffsets.containsKey(e.relativeFrom)) {
points.add(new Point(p.x, p.y + e.from.outOffsets.get(e.relativeFrom) + e.link.getFrom().getRelativePosition().y));
Point pOffset = new Point(p.x, p.y + e.from.outOffsets.get(e.relativeFrom) +
e.link.getFrom().getRelativePosition().y + e.from.yOffset);
if (!pOffset.equals(p)) {
points.add(pOffset);
}
}
LayoutNode cur = e.to;
@ -404,12 +465,12 @@ public class HierarchicalLayoutManager implements LayoutManager {
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));
points.add(0, new Point(p1.x + other.x + other.xOffset, p1.y + other.y));
}
}
if (reversedLinkEndPoints.containsKey(e.link)) {
for (Point p1 : reversedLinkEndPoints.get(e.link)) {
points.add(new Point(p1.x + cur.x, p1.y + cur.y));
points.add(new Point(p1.x + cur.x + cur.xOffset, p1.y + cur.y));
}
}
if (reversedLinks.contains(e.link)) {
@ -879,7 +940,7 @@ public class HierarchicalLayoutManager implements LayoutManager {
for (LayoutNode n : layers[index]) {
n.x = x;
x += n.width + X_OFFSET;
x += n.width + xOffset;
}
}
@ -1446,18 +1507,6 @@ public class HierarchicalLayoutManager implements LayoutManager {
@Override
protected void run() {
// Remove self-edges
for (LayoutNode node : nodes) {
ArrayList<LayoutEdge> succs = new ArrayList<>(node.succs);
for (LayoutEdge e : succs) {
assert e.from == node;
if (e.to == node) {
node.succs.remove(e);
node.preds.remove(e);
}
}
}
// Reverse inputs of roots
for (LayoutNode node : nodes) {
if (node.vertex.isRoot()) {
@ -1485,17 +1534,27 @@ public class HierarchicalLayoutManager implements LayoutManager {
SortedSet<Integer> reversedDown = new TreeSet<>();
boolean hasSelfEdge = false;
for (LayoutEdge e : node.succs) {
if (reversedLinks.contains(e.link)) {
reversedDown.add(e.relativeFrom);
if (e.from == e.to) {
hasSelfEdge = true;
}
}
}
// Whether the node has non-self reversed edges going downwards.
// If so, reversed edges going upwards are drawn to the left.
boolean hasReversedDown =
reversedDown.size() > 0 &&
!(reversedDown.size() == 1 && hasSelfEdge);
SortedSet<Integer> reversedUp = null;
if (reversedDown.size() == 0) {
reversedUp = new TreeSet<>(Collections.reverseOrder());
} else {
if (hasReversedDown) {
reversedUp = new TreeSet<>();
} else {
reversedUp = new TreeSet<>(Collections.reverseOrder());
}
for (LayoutEdge e : node.preds) {
@ -1504,7 +1563,7 @@ public class HierarchicalLayoutManager implements LayoutManager {
}
}
final int offset = X_OFFSET + DUMMY_WIDTH;
final int offset = xOffset + DUMMY_WIDTH;
int curX = 0;
int curWidth = node.width + reversedDown.size() * offset;
@ -1531,17 +1590,22 @@ public class HierarchicalLayoutManager implements LayoutManager {
node.yOffset += offset;
curWidth -= offset;
}
node.width += reversedDown.size() * offset;
if (reversedDown.size() == 0) {
curX = offset;
} else {
int widthFactor = reversedDown.size();
if (hasSelfEdge) {
widthFactor--;
}
node.width += widthFactor * offset;
if (hasReversedDown) {
curX = -offset;
} else {
curX = offset;
}
curX = 0;
int minX = 0;
if (reversedDown.size() != 0) {
if (hasReversedDown) {
minX = -offset * reversedUp.size();
}
@ -1550,10 +1614,10 @@ public class HierarchicalLayoutManager implements LayoutManager {
ArrayList<LayoutEdge> reversedPreds = new ArrayList<>();
for (LayoutEdge e : node.preds) {
if (e.relativeTo == pos && reversedLinks.contains(e.link)) {
if (reversedDown.size() == 0) {
e.relativeTo = node.width + offset;
} else {
if (hasReversedDown) {
e.relativeTo = curX - offset;
} else {
e.relativeTo = node.width + offset;
}
reversedPreds.add(e);
@ -1562,16 +1626,13 @@ public class HierarchicalLayoutManager implements LayoutManager {
node.height += offset;
ArrayList<Point> endPoints = new ArrayList<>();
if (reversedDown.size() == 0) {
curX += offset;
node.width += offset;
endPoints.add(new Point(node.width, node.height));
} else {
node.width += offset;
if (hasReversedDown) {
curX -= offset;
node.width += offset;
endPoints.add(new Point(curX, node.height));
} else {
curX += offset;
endPoints.add(new Point(node.width, node.height));
}
node.outOffsets.put(pos - minX, curX);
@ -1735,7 +1796,12 @@ public class HierarchicalLayoutManager implements LayoutManager {
protected void run() {
// Set up nodes
List<Vertex> vertices = new ArrayList<>(graph.getVertices());
Collections.sort(vertices);
// Order roots first to create more natural layer assignments.
Collections.sort(vertices,
(Vertex a, Vertex b) ->
a.isRoot() == b.isRoot() ?
a.compareTo(b) :
Boolean.compare(b.isRoot(), a.isRoot()));
for (Vertex v : vertices) {
LayoutNode node = new LayoutNode();
@ -1762,7 +1828,6 @@ public class HierarchicalLayoutManager implements LayoutManager {
edge.vip = l.isVIP();
edge.from.succs.add(edge);
edge.to.preds.add(edge);
//assert edge.from != edge.to; // No self-loops allowed
}
for (Link l : importantLinks) {
@ -1802,9 +1867,4 @@ public class HierarchicalLayoutManager implements LayoutManager {
}
}
}
@Override
public void doRouting(LayoutGraph graph) {
// Do nothing for now
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -25,6 +25,7 @@ package com.sun.hotspot.igv.hierarchicallayout;
import com.sun.hotspot.igv.layout.Link;
import com.sun.hotspot.igv.layout.Port;
import com.sun.hotspot.igv.layout.Cluster;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
@ -61,6 +62,14 @@ public class InterClusterConnection implements Link {
return outputSlot;
}
public Cluster getFromCluster() {
return null;
}
public Cluster getToCluster() {
return null;
}
public void setControlPoints(List<Point> p) {
this.intermediatePoints = p;
}

@ -0,0 +1,67 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package com.sun.hotspot.igv.hierarchicallayout;
import com.sun.hotspot.igv.layout.LayoutGraph;
import com.sun.hotspot.igv.layout.LayoutManager;
import com.sun.hotspot.igv.layout.Link;
import com.sun.hotspot.igv.layout.Vertex;
import java.awt.Point;
import java.util.*;
public class LinearLayoutManager implements LayoutManager {
// Ranking determining the vertical node ordering.
private final Map<? extends Vertex, Integer> vertexRank;
public LinearLayoutManager(Map<? extends Vertex, Integer> vertexRank) {
this.vertexRank = vertexRank;
}
@Override
public void doLayout(LayoutGraph graph) {
doLayout(graph, new HashSet<Link>());
}
@Override
public void doLayout(LayoutGraph graph, Set<? extends Link> importantLinks) {
assert (graph.getLinks().isEmpty());
// Sort vertices according to given rank.
List<Vertex> vertices = new ArrayList<>(graph.getVertices());
vertices.sort(Comparator.comparingInt((Vertex v) -> vertexRank.getOrDefault(v, Integer.MAX_VALUE)));
// Assign vertical coordinates in rank order.
assignVerticalCoordinates(vertices);
}
private void assignVerticalCoordinates(List<Vertex> vertices) {
int curY = 0;
for (Vertex v : vertices) {
v.setPosition(new Point(0, curY));
curY += v.getSize().getHeight();
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -23,6 +23,7 @@
*/
package com.sun.hotspot.igv.layout;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.util.Set;
@ -37,4 +38,6 @@ public interface Cluster extends Comparable<Cluster> {
public void setBounds(Rectangle r);
public Set<? extends Cluster> getSuccessors();
public Dimension getNodeOffset();
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -51,6 +51,9 @@ public class LayoutGraph {
outputPorts = new HashMap<>(links.size());
for (Link l : links) {
if (l.getFrom() == null || l.getTo() == null) {
continue;
}
Port p = l.getFrom();
Port p2 = l.getTo();
Vertex v1 = p.getVertex();
@ -195,4 +198,9 @@ public class LayoutGraph {
return clusters;
}
@Override
public String toString() {
return "LayoutGraph(" + vertices + ", " + links + ", " + getClusters() + ")";
}
}

@ -34,6 +34,4 @@ public interface LayoutManager {
public void doLayout(LayoutGraph graph);
public void doLayout(LayoutGraph graph, Set<? extends Link> importantLinks);
public void doRouting(LayoutGraph graph);
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -34,8 +34,12 @@ public interface Link {
public Port getFrom();
public Cluster getFromCluster();
public Port getTo();
public Cluster getToCluster();
public boolean isVIP();
public List<Point> getControlPoints();

@ -30,6 +30,7 @@ import com.sun.hotspot.igv.data.InputGraph;
import com.sun.hotspot.igv.data.InputNode;
import com.sun.hotspot.igv.data.services.Scheduler;
import java.util.*;
import java.util.function.Predicate;
import org.openide.ErrorManager;
import org.openide.util.lookup.ServiceProvider;
import com.ibm.wala.util.graph.Graph;
@ -52,6 +53,38 @@ public class ServerCompilerScheduler implements Scheduler {
public boolean isBlockProjection;
public boolean isBlockStart;
public boolean isCFG;
public int rank; // Rank for local scheduling priority.
public Node(InputNode n) {
inputNode = n;
String p = n.getProperties().get("is_block_proj");
isBlockProjection = (p != null && p.equals("true"));
p = n.getProperties().get("is_block_start");
isBlockStart = (p != null && p.equals("true"));
computeRank();
}
// Rank by local scheduling priority.
private void computeRank() {
if (isBlockStart || isOtherBlockStart(this)) {
rank = 1;
} else if (isPhi(this)) {
rank = 2;
} else if (isParm(this)) {
rank = 3;
} else if (isProj(this)) {
rank = 4;
} else if (!isControl(this)) { // Every other node except terminators.
rank = 5;
} else {
rank = 6;
}
}
@Override
public String toString() {
return inputNode.getProperties().get("idx") + " " + inputNode.getProperties().get("name");
}
}
private InputGraph graph;
private Collection<Node> nodes;
@ -80,15 +113,17 @@ public class ServerCompilerScheduler implements Scheduler {
Set<Node> visited = new HashSet<>();
Map<InputBlock, Set<Node>> terminators = new HashMap<>();
// Pre-compute control successors of each node, excluding self edges.
Map<Node, Set<Node>> controlSuccs = new HashMap<>();
Map<Node, List<Node>> controlSuccs = new HashMap<>();
for (Node n : nodes) {
if (n.isCFG) {
Set<Node> nControlSuccs = new HashSet<>();
List<Node> nControlSuccs = new ArrayList<>();
for (Node s : n.succs) {
if (s.isCFG && s != n) {
nControlSuccs.add(s);
}
}
// Ensure that the block ordering is deterministic.
nControlSuccs.sort(Comparator.comparingInt((Node a) -> a.inputNode.getId()));
controlSuccs.put(n, nControlSuccs);
}
}
@ -173,7 +208,18 @@ public class ServerCompilerScheduler implements Scheduler {
}
}
for (Node s : uniqueSuccs) {
graph.addBlockEdge(terms.getKey(), s.block);
// Label the block edge with the short name of the corresponding
// control projection, if any.
String label = null;
if (terms.getValue().size() > 1) {
for (Node t : terms.getValue()) {
if (s.preds.contains(t)) {
label = t.inputNode.getProperties().get("short_name");
break;
}
}
}
graph.addBlockEdge(terms.getKey(), s.block, label);
}
}
@ -237,7 +283,7 @@ public class ServerCompilerScheduler implements Scheduler {
for (InputNode n : graph.getNodes()) {
if (graph.getBlock(n) == null) {
if (noBlock == null) {
noBlock = graph.addBlock("(no block)");
noBlock = graph.addArtificialBlock();
blocks.add(noBlock);
}
@ -246,10 +292,104 @@ public class ServerCompilerScheduler implements Scheduler {
assert graph.getBlock(n) != null;
}
scheduleLocal();
return blocks;
}
}
private void scheduleLocal() {
// Leave only local predecessors and successors.
for (InputBlock b : blocks) {
for (InputNode in : b.getNodes()) {
Node n = inputNodeToNode.get(in);
Predicate<Node> excludePredecessors =
node -> isPhi(node) || node.isBlockStart;
List<Node> localPreds = new ArrayList<>(n.preds.size());
for (Node p : n.preds) {
if (p.block == b && p != n && !excludePredecessors.test(n)) {
localPreds.add(p);
}
}
n.preds = localPreds;
Set<Node> localSuccs = new HashSet<>(n.succs.size());
for (Node s : n.succs) {
if (s.block == b && s != n && !excludePredecessors.test(s)) {
localSuccs.add(s);
}
}
n.succs = localSuccs;
}
}
// Schedule each block independently.
for (InputBlock b : blocks) {
List<Node> nodes = new ArrayList<>(b.getNodes().size());
for (InputNode n : b.getNodes()) {
nodes.add(inputNodeToNode.get(n));
}
List<InputNode> schedule = scheduleBlock(nodes);
b.setNodes(schedule);
}
}
private static final Comparator<Node> schedulePriority = new Comparator<Node>(){
@Override
public int compare(Node n1, Node n2) {
// Order by rank, then idx.
int r1 = n1.rank, r2 = n2.rank;
int o1, o2;
if (r1 != r2) { // Different rank.
o1 = r1;
o2 = r2;
} else { // Same rank, order by idx.
o1 = Integer.parseInt(n1.inputNode.getProperties().get("idx"));
o2 = Integer.parseInt(n2.inputNode.getProperties().get("idx"));
}
return Integer.compare(o1, o2);
};
};
private List<InputNode> scheduleBlock(Collection<Node> nodes) {
List<InputNode> schedule = new ArrayList<InputNode>();
// Initialize ready priority queue with nodes without predecessors.
Queue<Node> ready = new PriorityQueue<Node>(schedulePriority);
// Set of nodes that have been enqueued.
Set<Node> visited = new HashSet<Node>(nodes.size());
for (Node n : nodes) {
if (n.preds.isEmpty()) {
ready.add(n);
visited.add(n);
}
}
// Classic list scheduling algorithm.
while (!ready.isEmpty()) {
Node n = ready.remove();
schedule.add(n.inputNode);
// Add nodes that are now ready after scheduling n.
for (Node s : n.succs) {
if (visited.contains(s)) {
continue;
}
boolean allPredsScheduled = true;
for (Node p : s.preds) {
if (!visited.contains(p)) {
allPredsScheduled = false;
break;
}
}
if (allPredsScheduled) {
ready.add(s);
visited.add(s);
}
}
}
assert(schedule.size() == nodes.size());
return schedule;
}
private void scheduleLatest() {
Node root = findRoot();
if(root == null) {
@ -426,12 +566,32 @@ public class ServerCompilerScheduler implements Scheduler {
}
}
private boolean isRegion(Node n) {
return n.inputNode.getProperties().get("name").equals("Region");
private static boolean isOtherBlockStart(Node n) {
return hasName(n, "CountedLoopEnd");
}
private boolean isPhi(Node n) {
return n.inputNode.getProperties().get("name").equals("Phi");
private static boolean isPhi(Node n) {
return hasName(n, "Phi");
}
private static boolean isProj(Node n) {
return hasName(n, "Proj") || hasName(n, "MachProj");
}
private static boolean isParm(Node n) {
return hasName(n, "Parm");
}
private static boolean hasName(Node n, String name) {
String nodeName = n.inputNode.getProperties().get("name");
if (nodeName == null) {
return false;
}
return nodeName.equals(name);
}
private static boolean isControl(Node n) {
return n.inputNode.getProperties().get("category").equals("control");
}
private Node findRoot() {
@ -439,9 +599,7 @@ public class ServerCompilerScheduler implements Scheduler {
Node alternativeRoot = null;
for (Node node : nodes) {
InputNode inputNode = node.inputNode;
String s = inputNode.getProperties().get("name");
if (s != null && s.equals("Root")) {
if (hasName(node, "Root")) {
return node;
}
@ -473,13 +631,8 @@ public class ServerCompilerScheduler implements Scheduler {
public void buildUpGraph() {
for (InputNode n : graph.getNodes()) {
Node node = new Node();
node.inputNode = n;
Node node = new Node(n);
nodes.add(node);
String p = n.getProperties().get("is_block_proj");
node.isBlockProjection = (p != null && p.equals("true"));
p = n.getProperties().get("is_block_start");
node.isBlockStart = (p != null && p.equals("true"));
inputNodeToNode.put(n, node);
}

@ -0,0 +1,18 @@
// Hide exception blocks.
var f = new RemoveBlockFilter("Hide exception blocks");
f.addRule(
new RemoveBlockFilter.RemoveBlockRule(
new AnySelector(
new OrSelector(
new MatcherSelector(
new Properties.StringPropertyMatcher("name", "Rethrow")
),
new MatcherSelector(
new Properties.StringPropertyMatcher("name", "RethrowException")
)
)
)
)
);
f.apply(graph);

@ -0,0 +1,13 @@
// Remove root block and all nodes in it (hopefully just the Root node).
var f = new RemoveBlockFilter("Hide root block");
f.addRule(
new RemoveBlockFilter.RemoveBlockRule(
new AnySelector(
new MatcherSelector(
new Properties.RegexpPropertyMatcher("name", "Root")
)
)
)
);
f.apply(graph);

@ -0,0 +1,13 @@
// Hide uncommon trap blocks.
var f = new RemoveBlockFilter("Hide uncommon trap blocks");
f.addRule(
new RemoveBlockFilter.RemoveBlockRule(
new AnySelector(
new MatcherSelector(
new Properties.RegexpPropertyMatcher("dump_spec", ".*uncommon_trap.*")
)
)
)
);
f.apply(graph);

@ -57,5 +57,17 @@
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Hide mixed edges"/>
</file>
<file name="Hide root block" url="filters/hideRootBlock.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Hide other edges"/>
</file>
<file name="Hide uncommon trap blocks" url="filters/hideUncommonTrapBlocks.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Hide root block"/>
</file>
<file name="Hide exception blocks" url="filters/hideExceptionBlocks.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Hide uncommon trap blocks"/>
</file>
</folder>
</filesystem>

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2022, 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
@ -32,12 +32,20 @@ import java.util.prefs.Preferences;
*/
public class Settings {
public static class DefaultView {
public static final int SEA_OF_NODES = 0;
public static final int CLUSTERED_SEA_OF_NODES = 1;
public static final int CONTROL_FLOW_GRAPH = 2;
}
public static final String NODE_TEXT = "nodeText";
public static final String NODE_TEXT_DEFAULT = "[idx] [name]";
public static final String NODE_SHORT_TEXT = "nodeShortText";
public static final String NODE_SHORT_TEXT_DEFAULT = "[idx] [name]";
public static final String NODE_WIDTH = "nodeWidth";
public static final String NODE_WIDTH_DEFAULT = "100";
public static final String NODE_TINY_TEXT = "nodeTinyText";
public static final String NODE_TINY_TEXT_DEFAULT = "[idx]";
public static final String DEFAULT_VIEW = "defaultView";
public static final int DEFAULT_VIEW_DEFAULT = DefaultView.SEA_OF_NODES;
public static final String PORT = "port";
public static final String PORT_BINARY = "portBinary";
public static final String PORT_DEFAULT = "4444";

@ -28,7 +28,7 @@
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="jPanel1" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="153" max="32767" attributes="0"/>
<EmptySpace pref="29" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -46,19 +46,17 @@
<Component id="jLabel3" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="jLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="jLabel4" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="jLabel5" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="39" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" alignment="0" groupAlignment="0" max="-2" attributes="0">
<Component id="nodeShortTextField" max="32767" attributes="0"/>
<Component id="jScrollPane1" pref="365" max="32767" attributes="0"/>
</Group>
<Group type="103" alignment="0" groupAlignment="1" max="-2" attributes="0">
<Component id="nodeWidthSpinner" alignment="0" pref="100" max="32767" attributes="0"/>
<Component id="portSpinner" alignment="0" max="32767" attributes="0"/>
</Group>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="nodeShortTextField" max="32767" attributes="0"/>
<Component id="jScrollPane1" pref="470" max="32767" attributes="0"/>
<Component id="portSpinner" alignment="0" max="32767" attributes="0"/>
<Component id="nodeTinyTextField" alignment="0" max="32767" attributes="0"/>
<Component id="defaultViewComboBox" alignment="0" max="32767" attributes="0"/>
</Group>
<EmptySpace pref="439" max="32767" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -77,8 +75,13 @@
</Group>
<EmptySpace pref="27" max="32767" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="nodeWidthSpinner" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jLabel5" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="nodeTinyTextField" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="27" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="defaultViewComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="27" max="32767" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
@ -97,7 +100,7 @@
</Component>
<Component class="javax.swing.JLabel" name="jLabel2">
<Properties>
<Property name="text" type="java.lang.String" value="Node Width"/>
<Property name="text" type="java.lang.String" value="Default View"/>
</Properties>
</Component>
<Component class="javax.swing.JSpinner" name="portSpinner">
@ -118,8 +121,6 @@
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JSpinner" name="nodeWidthSpinner">
</Component>
<Component class="javax.swing.JLabel" name="jLabel3">
<Properties>
<Property name="text" type="java.lang.String" value="Network Port"/>
@ -141,6 +142,37 @@
<AuxValue name="JavaCodeGenerator_SerializeTo" type="java.lang.String" value="ViewPanel_nodeShortTextField"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="jLabel5">
<Properties>
<Property name="text" type="java.lang.String" value="Tiny Node Text"/>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="nodeTinyTextField">
<Properties>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="ff" green="ff" red="ff" type="rgb"/>
</Property>
<Property name="toolTipText" type="java.lang.String" value="Single-line format string for node input lists. Properties are specified with brackets (example: &quot;[idx]&quot;)."/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_SerializeTo" type="java.lang.String" value="ViewPanel_nodeTinyTextField"/>
</AuxValues>
</Component>
<Component class="javax.swing.JComboBox" name="defaultViewComboBox">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="3">
<StringItem index="0" value="Sea of nodes"/>
<StringItem index="1" value="Clustered sea of nodes"/>
<StringItem index="2" value="Control-flow graph"/>
</StringArray>
</Property>
<Property name="toolTipText" type="java.lang.String" value="View shown by default when a graph is opened."/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
</SubComponents>

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -50,14 +50,16 @@ final class ViewPanel extends javax.swing.JPanel {
portSpinner = new javax.swing.JSpinner();
jScrollPane1 = new javax.swing.JScrollPane();
nodeTextArea = new javax.swing.JTextArea();
nodeWidthSpinner = new javax.swing.JSpinner();
jLabel3 = new javax.swing.JLabel();
jLabel4 = new javax.swing.JLabel();
nodeShortTextField = new javax.swing.JTextField();
jLabel5 = new javax.swing.JLabel();
nodeTinyTextField = new javax.swing.JTextField();
defaultViewComboBox = new javax.swing.JComboBox<>();
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, "Node Text");
org.openide.awt.Mnemonics.setLocalizedText(jLabel2, "Node Width");
org.openide.awt.Mnemonics.setLocalizedText(jLabel2, "Default View");
nodeTextArea.setColumns(20);
nodeTextArea.setRows(5);
@ -71,6 +73,14 @@ final class ViewPanel extends javax.swing.JPanel {
nodeShortTextField.setBackground(new java.awt.Color(255, 255, 255));
nodeShortTextField.setToolTipText("Single-line format string for nodes in edge tooltips, slot tooltips, and node search bar. Properties are specified with brackets (example: \"[idx]\").");
org.openide.awt.Mnemonics.setLocalizedText(jLabel5, "Tiny Node Text");
nodeTinyTextField.setBackground(new java.awt.Color(255, 255, 255));
nodeTinyTextField.setToolTipText("Single-line format string for node input lists. Properties are specified with brackets (example: \"[idx]\").");
defaultViewComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Sea of nodes", "Clustered sea of nodes", "Control-flow graph" }));
defaultViewComboBox.setToolTipText("View shown by default when a graph is opened.");
org.jdesktop.layout.GroupLayout jPanel1Layout = new org.jdesktop.layout.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
@ -81,16 +91,16 @@ final class ViewPanel extends javax.swing.JPanel {
.add(jLabel1)
.add(jLabel3)
.add(jLabel2)
.add(jLabel4))
.add(jLabel4)
.add(jLabel5))
.add(39, 39, 39)
.add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
.add(nodeShortTextField)
.add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 365, Short.MAX_VALUE))
.add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false)
.add(org.jdesktop.layout.GroupLayout.LEADING, nodeWidthSpinner, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 100, Short.MAX_VALUE)
.add(org.jdesktop.layout.GroupLayout.LEADING, portSpinner)))
.addContainerGap(439, Short.MAX_VALUE))
.add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
.add(nodeShortTextField)
.add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 470, Short.MAX_VALUE)
.add(portSpinner)
.add(nodeTinyTextField)
.add(defaultViewComboBox, 0, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
@ -105,8 +115,12 @@ final class ViewPanel extends javax.swing.JPanel {
.add(nodeShortTextField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 27, Short.MAX_VALUE)
.add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
.add(nodeWidthSpinner, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.add(jLabel2))
.add(jLabel5)
.add(nodeTinyTextField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.add(27, 27, 27)
.add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
.add(jLabel2)
.add(defaultViewComboBox, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 27, Short.MAX_VALUE)
.add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
.add(portSpinner, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
@ -127,20 +141,22 @@ final class ViewPanel extends javax.swing.JPanel {
.add(layout.createSequentialGroup()
.addContainerGap()
.add(jPanel1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addContainerGap(153, Short.MAX_VALUE))
.addContainerGap(29, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
void load() {
nodeTextArea.setText(Settings.get().get(Settings.NODE_TEXT, Settings.NODE_TEXT_DEFAULT));
nodeShortTextField.setText(Settings.get().get(Settings.NODE_SHORT_TEXT, Settings.NODE_SHORT_TEXT_DEFAULT));
nodeWidthSpinner.setValue(Integer.parseInt(Settings.get().get(Settings.NODE_WIDTH, Settings.NODE_WIDTH_DEFAULT)));
nodeTinyTextField.setText(Settings.get().get(Settings.NODE_TINY_TEXT, Settings.NODE_TINY_TEXT_DEFAULT));
defaultViewComboBox.setSelectedIndex(Settings.get().getInt(Settings.DEFAULT_VIEW, Settings.DefaultView.SEA_OF_NODES));
portSpinner.setValue(Integer.parseInt(Settings.get().get(Settings.PORT, Settings.PORT_DEFAULT)));
}
void store() {
Settings.get().put(Settings.NODE_TEXT, nodeTextArea.getText());
Settings.get().put(Settings.NODE_SHORT_TEXT, nodeShortTextField.getText());
Settings.get().put(Settings.NODE_WIDTH, nodeWidthSpinner.getValue().toString());
Settings.get().put(Settings.NODE_TINY_TEXT, nodeTinyTextField.getText());
Settings.get().putInt(Settings.DEFAULT_VIEW, defaultViewComboBox.getSelectedIndex());
Settings.get().put(Settings.PORT, portSpinner.getValue().toString());
}
@ -148,15 +164,17 @@ final class ViewPanel extends javax.swing.JPanel {
return true;
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JComboBox<String> defaultViewComboBox;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel jLabel3;
private javax.swing.JLabel jLabel4;
private javax.swing.JLabel jLabel5;
private javax.swing.JPanel jPanel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTextField nodeShortTextField;
private javax.swing.JTextArea nodeTextArea;
private javax.swing.JSpinner nodeWidthSpinner;
private javax.swing.JTextField nodeTinyTextField;
private javax.swing.JSpinner portSpinner;
// End of variables declaration//GEN-END:variables
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2022, 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
@ -113,4 +113,25 @@ public class StringUtils {
}
}
/**
* Rank a match of a query in a word. Full matches of a word rank highest,
* followed by partial matches at the word start, followed by the rest of
* matches in increasing size of the partially matched word, for example:
*
* rank("5", "5") = 1 (full match)
* rank("5", "554") = 2 (start match)
* rank("5", "25") = 3 (middle match with excess 1)
* rank("5", "253") = 4 (middle match with excess 2)
*/
public static int rankMatch(String query, String word) {
if (word.equals(query)) {
return 1;
} else if (word.startsWith(query)) {
return 2;
} else if (word.contains(query)) {
return word.length() - query.length() + 2;
}
return Integer.MAX_VALUE;
}
}

@ -0,0 +1,146 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package com.sun.hotspot.igv.view;
import com.sun.hotspot.igv.data.InputGraph;
import com.sun.hotspot.igv.data.InputBlock;
import com.sun.hotspot.igv.data.Properties.RegexpPropertyMatcher;
import com.sun.hotspot.igv.data.services.InputGraphProvider;
import com.sun.hotspot.igv.util.LookupHistory;
import com.sun.hotspot.igv.util.StringUtils;
import java.util.List;
import java.util.ArrayList;
import java.util.regex.Pattern;
import org.netbeans.spi.quicksearch.SearchProvider;
import org.netbeans.spi.quicksearch.SearchRequest;
import org.netbeans.spi.quicksearch.SearchResponse;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.NotifyDescriptor.Message;
public class BlockQuickSearch implements SearchProvider {
@Override
public void evaluate(SearchRequest request, SearchResponse response) {
String rawValue = request.getText();
if (rawValue.trim().isEmpty()) {
return;
}
String value = ".*" + Pattern.quote(rawValue) + ".*";
final InputGraphProvider p = LookupHistory.getLast(InputGraphProvider.class);
if (p == null || p.getGraph() == null) {
return;
}
InputGraph matchGraph = p.getGraph();
// Search the current graph
List<InputBlock> matches = findMatches(value, p.getGraph(), response);
if (matches == null) {
// See if the it hits in a later graph
for (InputGraph graph : p.searchForward()) {
matches = findMatches(value, graph, response);
if (matches != null) {
matchGraph = graph;
break;
}
}
}
if (matches == null) {
// See if it hits in a earlier graph
for (InputGraph graph : p.searchBackward()) {
matches = findMatches(value, graph, response);
if (matches != null) {
matchGraph = graph;
break;
}
}
}
if (matches != null) {
// Rank the matches.
matches.sort((InputBlock a, InputBlock b) ->
compareByRankThenNumVal(rawValue,
"B" + a.getName(),
"B" + b.getName()));
final InputGraph theGraph = p.getGraph() != matchGraph ? matchGraph : null;
for (final InputBlock b : matches) {
if (!response.addResult(() -> {
final EditorTopComponent comp = EditorTopComponent.getActive();
assert(comp != null);
if (theGraph != null) {
comp.getDiagramModel().selectGraph(theGraph);
}
comp.setSelectedNodes(b);
comp.requestActive();
},
"B" + b.getName() + (theGraph != null ? " in " + theGraph.getName() : ""))) {
return;
}
}
}
}
private List<InputBlock> findMatches(String blockName, InputGraph inputGraph, SearchResponse response) {
try {
RegexpPropertyMatcher matcher = new RegexpPropertyMatcher("", blockName, Pattern.CASE_INSENSITIVE);
List<InputBlock> matches = new ArrayList<>();
for (InputBlock b : inputGraph.getBlocks()) {
if (matcher.match("B" + b.getName())) {
matches.add(b);
}
}
return matches.size() == 0 ? null : matches;
} catch (Exception e) {
final String msg = e.getMessage();
response.addResult(() -> {
Message desc = new NotifyDescriptor.Message("An exception occurred during the search, "
+ "perhaps due to a malformed query string:\n" + msg,
NotifyDescriptor.WARNING_MESSAGE);
DialogDisplayer.getDefault().notify(desc);
},
"(Error during search)"
);
}
return null;
}
private int compareByRankThenNumVal(String qry, String b1, String b2) {
int key1 = StringUtils.rankMatch(qry, b1);
int key2 = StringUtils.rankMatch(qry, b2);
if (key1 == key2) {
// If the matches have the same rank, compare the numeric values of
// their first words, if applicable.
try {
key1 = Integer.parseInt(b1.replace("B", ""));
key2 = Integer.parseInt(b2.replace("B", ""));
} catch (Exception e) {
// Not applicable, return equality value.
return 0;
}
}
return Integer.compare(key1, key2);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -32,8 +32,11 @@ import com.sun.hotspot.igv.data.Properties;
import com.sun.hotspot.igv.data.services.Scheduler;
import com.sun.hotspot.igv.graph.*;
import com.sun.hotspot.igv.hierarchicallayout.HierarchicalClusterLayoutManager;
import com.sun.hotspot.igv.hierarchicallayout.HierarchicalCFGLayoutManager;
import com.sun.hotspot.igv.hierarchicallayout.LinearLayoutManager;
import com.sun.hotspot.igv.hierarchicallayout.HierarchicalLayoutManager;
import com.sun.hotspot.igv.layout.LayoutGraph;
import com.sun.hotspot.igv.layout.Link;
import com.sun.hotspot.igv.selectioncoordinator.SelectionCoordinator;
import com.sun.hotspot.igv.util.ColorIcon;
import com.sun.hotspot.igv.util.DoubleClickAction;
@ -493,6 +496,19 @@ public class DiagramScene extends ObjectScene implements DiagramViewer {
return a;
}
public Action createGotoAction(final Block b) {
final DiagramScene diagramScene = this;
String name = "B" + b.getInputBlock().getName();
Action a = new AbstractAction(name) {
@Override
public void actionPerformed(ActionEvent e) {
diagramScene.gotoBlock(b);
}
};
a.setEnabled(true);
return a;
}
public void setNewModel(DiagramViewModel model) {
assert this.model == null : "can set model only once!";
this.model = model;
@ -518,15 +534,26 @@ public class DiagramScene extends ObjectScene implements DiagramViewer {
Diagram d = getModel().getDiagramToView();
if (d.getGraph().getBlocks().isEmpty()) {
Scheduler s = Lookup.getDefault().lookup(Scheduler.class);
d.getGraph().clearBlocks();
s.schedule(d.getGraph());
d.getGraph().ensureNodesInBlocks();
d.updateBlocks();
Map<InputBlock, Integer> maxWidth = new HashMap<>();
for (InputBlock b : d.getGraph().getBlocks()) {
maxWidth.put(b, 10);
}
for (Figure f : d.getFigures()) {
// Update node text, since it might differ across views.
f.updateLines();
// Compute max node width in each block.
if (f.getWidth() > maxWidth.get(f.getBlock())) {
maxWidth.put(f.getBlock(), f.getWidth());
}
}
for (Figure f : d.getFigures()) {
// Set all nodes' width to the maximum width in the blocks?
if (getModel().getShowCFG()) {
f.setWidth(maxWidth.get(f.getBlock()));
}
FigureWidget w = new FigureWidget(f, hoverAction, selectAction, this, mainLayer);
w.getActions().addAction(ActionFactory.createPopupMenuAction(w));
w.getActions().addAction(selectAction);
@ -552,7 +579,7 @@ public class DiagramScene extends ObjectScene implements DiagramViewer {
}
}
if (getModel().getShowBlocks()) {
if (getModel().getShowBlocks() || getModel().getShowCFG()) {
for (InputBlock bn : d.getGraph().getBlocks()) {
BlockWidget w = new BlockWidget(this, d, bn);
w.setVisible(false);
@ -578,8 +605,11 @@ public class DiagramScene extends ObjectScene implements DiagramViewer {
}
private boolean isVisible(Connection c) {
FigureWidget w1 = getWidget(c.getInputSlot().getFigure());
FigureWidget w2 = getWidget(c.getOutputSlot().getFigure());
if (getModel().getShowCFG()) {
return c.isAlwaysVisible();
}
FigureWidget w1 = getWidget(c.getFrom().getVertex());
FigureWidget w2 = getWidget(c.getTo().getVertex());
if (w1.isVisible() && w2.isVisible()) {
return true;
@ -608,22 +638,72 @@ public class DiagramScene extends ObjectScene implements DiagramViewer {
}
}
if (getModel().getShowBlocks()) {
HierarchicalClusterLayoutManager m = new HierarchicalClusterLayoutManager(HierarchicalLayoutManager.Combine.SAME_OUTPUTS);
HierarchicalLayoutManager manager = new HierarchicalLayoutManager(HierarchicalLayoutManager.Combine.SAME_OUTPUTS);
manager.setMaxLayerLength(9);
manager.setMinLayerDifference(3);
m.setManager(manager);
m.setSubManager(new HierarchicalLayoutManager(HierarchicalLayoutManager.Combine.SAME_OUTPUTS));
m.doLayout(new LayoutGraph(edges, figures));
} else {
HierarchicalLayoutManager manager = new HierarchicalLayoutManager(HierarchicalLayoutManager.Combine.SAME_OUTPUTS);
manager.setMaxLayerLength(10);
manager.doLayout(new LayoutGraph(edges, figures));
if (getModel().getShowSea()) {
doSeaLayout(figures, edges);
} else if (getModel().getShowBlocks()) {
doClusteredLayout(figures, edges);
} else if (getModel().getShowCFG()) {
doCFGLayout(figures, edges);
}
relayoutWithoutLayout(oldVisibleWidgets);
}
private void doSeaLayout(HashSet<Figure> figures, HashSet<Connection> edges) {
HierarchicalLayoutManager manager = new HierarchicalLayoutManager(HierarchicalLayoutManager.Combine.SAME_OUTPUTS);
manager.setMaxLayerLength(10);
manager.doLayout(new LayoutGraph(edges, figures));
}
private void doClusteredLayout(HashSet<Figure> figures, HashSet<Connection> edges) {
HierarchicalClusterLayoutManager m = new HierarchicalClusterLayoutManager(HierarchicalLayoutManager.Combine.SAME_OUTPUTS);
HierarchicalLayoutManager manager = new HierarchicalLayoutManager(HierarchicalLayoutManager.Combine.SAME_OUTPUTS);
manager.setMaxLayerLength(9);
manager.setMinLayerDifference(3);
m.setManager(manager);
m.setSubManager(new HierarchicalLayoutManager(HierarchicalLayoutManager.Combine.SAME_OUTPUTS));
m.doLayout(new LayoutGraph(edges, figures));
}
private void doCFGLayout(HashSet<Figure> figures, HashSet<Connection> edges) {
Diagram diagram = getModel().getDiagramToView();
HierarchicalCFGLayoutManager m = new HierarchicalCFGLayoutManager();
HierarchicalLayoutManager manager = new HierarchicalLayoutManager(HierarchicalLayoutManager.Combine.SAME_OUTPUTS);
manager.setMaxLayerLength(9);
manager.setMinLayerDifference(1);
manager.setLayoutSelfEdges(true);
manager.setXOffset(25);
manager.setLayerOffset(25);
m.setManager(manager);
Map<InputNode, Figure> nodeFig = new HashMap<InputNode, Figure>();
for (Figure f : figures) {
InputNode n = f.getFirstSourceNode();
if (n != null) {
nodeFig.put(n, f);
}
}
// Compute global ranking among figures given by in-block order. If
// needed, this could be cached as long as it is computed for all the
// figures in the model, not just the visible ones.
Map<Figure, Integer> figureRank =
new HashMap<Figure, Integer>(figures.size());
int r = 0;
for (InputBlock b : getModel().getGraphToView().getBlocks()) {
for (InputNode n : b.getNodes()) {
Figure f = nodeFig.get(n);
if (f != null) {
figureRank.put(f, r);
r++;
}
}
}
// Add connections for CFG edges.
edges.addAll(diagram.getBlockConnections());
m.setSubManager(new LinearLayoutManager(figureRank));
m.setClusters(new HashSet<>(diagram.getBlocks()));
m.doLayout(new LayoutGraph(edges, figures));
}
private Set<Pair<Point, Point>> lineCache = new HashSet<>();
private void relayoutWithoutLayout(Set<Widget> oldVisibleWidgets) {
@ -642,7 +722,7 @@ public class DiagramScene extends ObjectScene implements DiagramViewer {
}
}
for (Connection c : diagram.getConnections()) {
for (FigureConnection c : diagram.getConnections()) {
List<Point> points = c.getControlPoints();
FigureWidget w1 = getWidget((Figure) c.getTo().getVertex());
FigureWidget w2 = getWidget((Figure) c.getFrom().getVertex());
@ -656,7 +736,7 @@ public class DiagramScene extends ObjectScene implements DiagramViewer {
}
}
if (getModel().getShowBlocks()) {
if (getModel().getShowBlocks() || getModel().getShowCFG()) {
for (Block b : diagram.getBlocks()) {
BlockWidget w = getWidget(b.getInputBlock());
if (w != null && w.isVisible()) {
@ -705,7 +785,18 @@ public class DiagramScene extends ObjectScene implements DiagramViewer {
if (visibleFigureCount > ANIMATION_LIMIT || oldVisibleWidgets == null) {
anim = null;
}
processOutputSlot(lastLineCache, s, s.getConnections(), 0, null, null, offx2, offy2, anim);
List<Connection> cl = new ArrayList<>(s.getConnections().size());
for (FigureConnection c : s.getConnections()) {
cl.add((Connection) c);
}
processOutputSlot(lastLineCache, s, cl, 0, null, null, offx2, offy2, anim);
}
}
if (getModel().getShowCFG()) {
for (BlockConnection c : diagram.getBlockConnections()) {
SceneAnimator anim = animator;
processOutputSlot(lastLineCache, null, Collections.singletonList(c), 0, null, null, offx2, offy2, anim);
}
}
@ -723,7 +814,7 @@ public class DiagramScene extends ObjectScene implements DiagramViewer {
}
}
if (getModel().getShowBlocks()) {
if (getModel().getShowBlocks() || getModel().getShowCFG()) {
for (Block b : diagram.getBlocks()) {
BlockWidget w = getWidget(b.getInputBlock());
if (w != null && w.isVisible()) {
@ -759,12 +850,15 @@ public class DiagramScene extends ObjectScene implements DiagramViewer {
}
Point cur = controlPoints.get(controlPointIndex);
if (cur == null) {
if (cur == null) { // Long connection, has been cut vertically.
cur = specialNullPoint;
} else if (controlPointIndex == 0 && !s.shouldShowName()) {
cur = new Point(cur.x, cur.y - SLOT_OFFSET);
} else if (controlPointIndex == controlPoints.size() - 1 && !c.getInputSlot().shouldShowName()) {
cur = new Point(cur.x, cur.y + SLOT_OFFSET);
} else if (c.hasSlots()) {
if (controlPointIndex == 0 && !s.shouldShowName()) {
cur = new Point(cur.x, cur.y - SLOT_OFFSET);
} else if (controlPointIndex == controlPoints.size() - 1 &&
!((Slot)c.getTo()).shouldShowName()) {
cur = new Point(cur.x, cur.y + SLOT_OFFSET);
}
}
if (pointMap.containsKey(cur)) {
@ -883,6 +977,13 @@ public class DiagramScene extends ObjectScene implements DiagramViewer {
}
}
public void gotoBlock(final Block block) {
BlockWidget bw = getWidget(block.getInputBlock());
if (bw != null) {
centerRectangle(bw.getBounds());
}
}
private Set<Object> idSetToObjectSet(Set<Object> ids) {
Set<Object> result = new HashSet<>();
@ -1042,7 +1143,7 @@ public class DiagramScene extends ObjectScene implements DiagramViewer {
}
}
if (getModel().getShowBlocks()) {
if (getModel().getShowBlocks() || getModel().getShowCFG()) {
for (InputBlock b : diagram.getGraph().getBlocks()) {
BlockWidget w = getWidget(b);
if (w.isVisible()) {
@ -1102,7 +1203,23 @@ public class DiagramScene extends ObjectScene implements DiagramViewer {
}
}
if (getModel().getShowBlocks()) {
if (getModel().getShowCFG()) {
// Blockless figures and artificial blocks are hidden in this view.
for (Figure f : diagram.getFigures()) {
if (f.getBlock().isArtificial()) {
FigureWidget w = getWidget(f);
w.setVisible(false);
}
}
visibleBlocks.clear();
for (InputBlock b : diagram.getGraph().getBlocks()) {
if (!b.isArtificial()) {
visibleBlocks.add(b);
}
}
}
if (getModel().getShowBlocks() || getModel().getShowCFG()) {
for (InputBlock b : diagram.getGraph().getBlocks()) {
boolean visibleAfter = visibleBlocks.contains(b);

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2022, 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
@ -25,6 +25,7 @@
package com.sun.hotspot.igv.view;
import com.sun.hotspot.igv.data.*;
import com.sun.hotspot.igv.data.services.Scheduler;
import com.sun.hotspot.igv.difference.Difference;
import com.sun.hotspot.igv.filter.CustomFilter;
import com.sun.hotspot.igv.filter.FilterChain;
@ -34,6 +35,7 @@ import com.sun.hotspot.igv.settings.Settings;
import com.sun.hotspot.igv.util.RangeSliderModel;
import java.awt.Color;
import java.util.*;
import org.openide.util.Lookup;
/**
*
@ -56,7 +58,9 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene
private ChangedEvent<DiagramViewModel> viewChangedEvent;
private ChangedEvent<DiagramViewModel> hiddenNodesChangedEvent;
private ChangedEvent<DiagramViewModel> viewPropertiesChangedEvent;
private boolean showSea;
private boolean showBlocks;
private boolean showCFG;
private boolean showNodeHull;
private boolean hideDuplicates;
private ChangedListener<FilterChain> filterChainChangedListener = new ChangedListener<FilterChain>() {
@ -102,8 +106,12 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene
this.onScreenNodes = newModel.onScreenNodes;
viewChanged |= (selectedNodes != newModel.selectedNodes);
this.selectedNodes = newModel.selectedNodes;
viewPropertiesChanged |= (showSea != newModel.showSea);
this.showSea = newModel.showSea;
viewPropertiesChanged |= (showBlocks != newModel.showBlocks);
this.showBlocks = newModel.showBlocks;
viewPropertiesChanged |= (showCFG != newModel.showCFG);
this.showCFG = newModel.showCFG;
viewPropertiesChanged |= (showNodeHull != newModel.showNodeHull);
this.showNodeHull = newModel.showNodeHull;
@ -122,6 +130,15 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene
}
}
public boolean getShowSea() {
return showSea;
}
public void setShowSea(boolean b) {
showSea = b;
viewPropertiesChangedEvent.fire();
}
public boolean getShowBlocks() {
return showBlocks;
}
@ -131,6 +148,15 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene
viewPropertiesChangedEvent.fire();
}
public boolean getShowCFG() {
return showCFG;
}
public void setShowCFG(boolean b) {
showCFG = b;
viewPropertiesChangedEvent.fire();
}
public boolean getShowNodeHull() {
return showNodeHull;
}
@ -164,7 +190,9 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene
public DiagramViewModel(Group g, FilterChain filterChain, FilterChain sequenceFilterChain) {
super(Arrays.asList("default"));
this.showBlocks = false;
this.showSea = Settings.get().getInt(Settings.DEFAULT_VIEW, Settings.DEFAULT_VIEW_DEFAULT) == Settings.DefaultView.SEA_OF_NODES;
this.showBlocks = Settings.get().getInt(Settings.DEFAULT_VIEW, Settings.DEFAULT_VIEW_DEFAULT) == Settings.DefaultView.CLUSTERED_SEA_OF_NODES;
this.showCFG = Settings.get().getInt(Settings.DEFAULT_VIEW, Settings.DEFAULT_VIEW_DEFAULT) == Settings.DefaultView.CONTROL_FLOW_GRAPH;
this.showNodeHull = true;
this.group = g;
filterGraphs();
@ -406,9 +434,17 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene
public Diagram getDiagramToView() {
if (diagram == null) {
diagram = Diagram.createDiagram(getGraphToView(),
InputGraph graph = getGraphToView();
if (graph.getBlocks().isEmpty()) {
Scheduler s = Lookup.getDefault().lookup(Scheduler.class);
graph.clearBlocks();
s.schedule(graph);
graph.ensureNodesInBlocks();
}
diagram = Diagram.createDiagram(graph,
Settings.get().get(Settings.NODE_TEXT, Settings.NODE_TEXT_DEFAULT),
Settings.get().get(Settings.NODE_SHORT_TEXT, Settings.NODE_SHORT_TEXT_DEFAULT));
Settings.get().get(Settings.NODE_SHORT_TEXT, Settings.NODE_SHORT_TEXT_DEFAULT),
Settings.get().get(Settings.NODE_TINY_TEXT, Settings.NODE_TINY_TEXT_DEFAULT));
getFilterChain().apply(diagram, getSequenceFilterChain());
if (getFirstPosition() != getSecondPosition()) {
CustomFilter f = new CustomFilter(
@ -420,6 +456,7 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene
}
}
diagram.setCFG(getShowCFG());
return diagram;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -28,6 +28,7 @@ import com.sun.hotspot.igv.data.ChangedListener;
import com.sun.hotspot.igv.data.GraphDocument;
import com.sun.hotspot.igv.data.Group;
import com.sun.hotspot.igv.data.InputNode;
import com.sun.hotspot.igv.data.InputBlock;
import com.sun.hotspot.igv.data.Properties;
import com.sun.hotspot.igv.data.Properties.PropertyMatcher;
import com.sun.hotspot.igv.data.services.InputGraphProvider;
@ -38,6 +39,7 @@ import com.sun.hotspot.igv.graph.Figure;
import com.sun.hotspot.igv.graph.services.DiagramProvider;
import com.sun.hotspot.igv.util.LookupHistory;
import com.sun.hotspot.igv.util.RangeSlider;
import com.sun.hotspot.igv.settings.Settings;
import com.sun.hotspot.igv.view.actions.*;
import java.awt.*;
import java.awt.event.HierarchyBoundsListener;
@ -91,7 +93,9 @@ public final class EditorTopComponent extends TopComponent implements PropertyCh
private DiagramViewer scene;
private InstanceContent content;
private InstanceContent graphContent;
private EnableSeaLayoutAction seaLayoutAction;
private EnableBlockLayoutAction blockLayoutAction;
private EnableCFGLayoutAction cfgLayoutAction;
private OverviewAction overviewAction;
private HideDuplicatesAction hideDuplicatesAction;
private PredSuccAction predSuccAction;
@ -238,12 +242,31 @@ public final class EditorTopComponent extends TopComponent implements PropertyCh
toolBar.add(ShowAllAction.get(ZoomInAction.class));
toolBar.add(ShowAllAction.get(ZoomOutAction.class));
toolBar.addSeparator();
ButtonGroup layoutButtons = new ButtonGroup();
seaLayoutAction = new EnableSeaLayoutAction();
JToggleButton button = new JToggleButton(seaLayoutAction);
button.setSelected(Settings.get().getInt(Settings.DEFAULT_VIEW, Settings.DEFAULT_VIEW_DEFAULT) == Settings.DefaultView.SEA_OF_NODES);
layoutButtons.add(button);
toolBar.add(button);
seaLayoutAction.addPropertyChangeListener(this);
blockLayoutAction = new EnableBlockLayoutAction();
JToggleButton button = new JToggleButton(blockLayoutAction);
button.setSelected(false);
button = new JToggleButton(blockLayoutAction);
button.setSelected(Settings.get().getInt(Settings.DEFAULT_VIEW, Settings.DEFAULT_VIEW_DEFAULT) == Settings.DefaultView.CLUSTERED_SEA_OF_NODES);
layoutButtons.add(button);
toolBar.add(button);
blockLayoutAction.addPropertyChangeListener(this);
cfgLayoutAction = new EnableCFGLayoutAction();
button = new JToggleButton(cfgLayoutAction);
button.setSelected(Settings.get().getInt(Settings.DEFAULT_VIEW, Settings.DEFAULT_VIEW_DEFAULT) == Settings.DefaultView.CONTROL_FLOW_GRAPH);
layoutButtons.add(button);
toolBar.add(button);
cfgLayoutAction.addPropertyChangeListener(this);
toolBar.addSeparator();
overviewAction = new OverviewAction();
overviewButton = new JToggleButton(overviewAction);
overviewButton.setSelected(false);
@ -508,6 +531,16 @@ public final class EditorTopComponent extends TopComponent implements PropertyCh
setSelectedFigures(list);
}
public void setSelectedNodes(InputBlock b) {
List<Figure> list = new ArrayList<>();
for (Figure f : getModel().getDiagramToView().getFigures()) {
if (f.getBlock() == b) {
list.add(f);
}
}
setSelectedFigures(list);
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getSource() == this.predSuccAction) {
@ -520,9 +553,15 @@ public final class EditorTopComponent extends TopComponent implements PropertyCh
} else {
showScene();
}
} else if (evt.getSource() == this.seaLayoutAction) {
boolean b = seaLayoutAction.isSelected();
this.getModel().setShowSea(b);
} else if (evt.getSource() == this.blockLayoutAction) {
boolean b = (Boolean) blockLayoutAction.getValue(EnableBlockLayoutAction.STATE);
boolean b = blockLayoutAction.isSelected();
this.getModel().setShowBlocks(b);
} else if (evt.getSource() == this.cfgLayoutAction) {
boolean b = cfgLayoutAction.isSelected();
this.getModel().setShowCFG(b);
} else if (evt.getSource() == this.hideDuplicatesAction) {
boolean b = (Boolean) hideDuplicatesAction.getValue(HideDuplicatesAction.STATE);
this.getModel().setHideDuplicates(b);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -66,8 +66,10 @@ public class GraphViewerImplementation implements GraphViewer {
Diagram diagram = Diagram.createDiagram(graph,
Settings.get().get(Settings.NODE_TEXT, Settings.NODE_TEXT_DEFAULT),
Settings.get().get(Settings.NODE_SHORT_TEXT, Settings.NODE_SHORT_TEXT_DEFAULT));
Settings.get().get(Settings.NODE_SHORT_TEXT, Settings.NODE_SHORT_TEXT_DEFAULT),
Settings.get().get(Settings.NODE_TINY_TEXT, Settings.NODE_TINY_TEXT_DEFAULT));
EditorTopComponent tc = new EditorTopComponent(diagram);
diagram.setCFG(tc.getModel().getShowCFG());
tc.open();
tc.requestActive();
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -30,6 +30,7 @@ import com.sun.hotspot.igv.data.Properties.RegexpPropertyMatcher;
import com.sun.hotspot.igv.data.services.InputGraphProvider;
import com.sun.hotspot.igv.settings.Settings;
import com.sun.hotspot.igv.util.LookupHistory;
import com.sun.hotspot.igv.util.StringUtils;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@ -214,24 +215,16 @@ public class NodeQuickSearch implements SearchProvider {
/**
* Rank a match by splitting the property into words. Full matches of a word
* rank highest, followed by partial matches at the word start, followed by
* the rest of matches in increasing size of the partially matched word, for
* example:
*
* rank("5", "5 AddI") = 1 (full match of first word)
* rank("5", "554 MulI") = 2 (start match of first word)
* rank("5", "25 AddL") = 3 (middle match of first word with excess 1)
* rank("5", "253 AddL") = 4 (middle match of first word with excess 2)
* the rest of matches in increasing size of the partially matched word. See
* examples in class StringUtils.
*/
private int rankMatch(String qry, String prop) {
String query = qry.toLowerCase();
String property = prop.toLowerCase();
for (String component : property.split("\\W+")) {
if (component.equals(query)) {
return 1;
} else if (component.startsWith(query)) {
return 2;
} else if (component.contains(query)) {
return component.length() - query.length() + 2;
int rank = StringUtils.rankMatch(query, component);
if (rank != Integer.MAX_VALUE) {
return rank;
}
}
return Integer.MAX_VALUE;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -35,22 +35,22 @@ import org.openide.util.ImageUtilities;
*/
public class EnableBlockLayoutAction extends AbstractAction {
private boolean state;
public static final String STATE = "state";
public EnableBlockLayoutAction() {
state = false;
putValue(AbstractAction.SMALL_ICON, new ImageIcon(ImageUtilities.loadImage(iconResource())));
putValue(STATE, state);
putValue(Action.SHORT_DESCRIPTION, "Cluster nodes into blocks");
putValue(SELECTED_KEY, false);
putValue(Action.SHORT_DESCRIPTION, "Show clustered sea of nodes");
}
public void actionPerformed(ActionEvent ev) {
this.state = !state;
this.putValue(STATE, state);
public boolean isSelected() {
return (Boolean)getValue(SELECTED_KEY);
}
protected String iconResource() {
return "com/sun/hotspot/igv/view/images/blocks.gif";
return "com/sun/hotspot/igv/view/images/blocks.png";
}
@Override
public void actionPerformed(ActionEvent e) {
}
}

@ -0,0 +1,51 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package com.sun.hotspot.igv.view.actions;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import org.openide.util.ImageUtilities;
public class EnableCFGLayoutAction extends AbstractAction {
public EnableCFGLayoutAction() {
putValue(AbstractAction.SMALL_ICON, new ImageIcon(ImageUtilities.loadImage(iconResource())));
putValue(SELECTED_KEY, false);
putValue(Action.SHORT_DESCRIPTION, "Show control-flow graph");
}
public boolean isSelected() {
return (Boolean)getValue(SELECTED_KEY);
}
protected String iconResource() {
return "com/sun/hotspot/igv/view/images/cfg.png";
}
@Override
public void actionPerformed(ActionEvent e) {
}
}

@ -0,0 +1,51 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package com.sun.hotspot.igv.view.actions;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import org.openide.util.ImageUtilities;
public class EnableSeaLayoutAction extends AbstractAction {
public EnableSeaLayoutAction() {
putValue(AbstractAction.SMALL_ICON, new ImageIcon(ImageUtilities.loadImage(iconResource())));
putValue(SELECTED_KEY, false);
putValue(Action.SHORT_DESCRIPTION, "Show sea of nodes");
}
public boolean isSelected() {
return (Boolean)getValue(SELECTED_KEY);
}
protected String iconResource() {
return "com/sun/hotspot/igv/view/images/sea.png";
}
@Override
public void actionPerformed(ActionEvent e) {
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -43,7 +43,8 @@ public class BlockWidget extends Widget {
public static final int BORDER = 20;
public static final Color BACKGROUND_COLOR = new Color(235, 235, 255);
private static final Font titleFont = new Font("Serif", Font.PLAIN, 14).deriveFont(Font.BOLD);
private static final Font TITLE_FONT = new Font("Arial", Font.BOLD, 14);
public static final Color TITLE_COLOR = new Color(42, 42, 171);
private InputBlock blockNode;
private Diagram diagram;
@ -70,9 +71,8 @@ public class BlockWidget extends Widget {
g.drawRect(r.x, r.y, r.width, r.height);
}
Color titleColor = Color.BLACK;
g.setColor(titleColor);
g.setFont(titleFont);
g.setColor(TITLE_COLOR);
g.setFont(TITLE_FONT);
String s = "B" + blockNode.getName();
Rectangle2D r1 = g.getFontMetrics().getStringBounds(s, g);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -46,6 +46,7 @@ import javax.swing.event.MenuListener;
import org.netbeans.api.visual.action.PopupMenuProvider;
import org.netbeans.api.visual.action.WidgetAction;
import org.netbeans.api.visual.layout.LayoutFactory;
import org.netbeans.api.visual.layout.LayoutFactory.SerialAlignment;
import org.netbeans.api.visual.model.ObjectState;
import org.netbeans.api.visual.widget.LabelWidget;
import org.netbeans.api.visual.widget.Widget;
@ -106,14 +107,20 @@ public class FigureWidget extends Widget implements Properties.Provider, PopupMe
outer.setLayout(LayoutFactory.createOverlayLayout());
middleWidget = new Widget(scene);
middleWidget.setLayout(LayoutFactory.createVerticalFlowLayout(LayoutFactory.SerialAlignment.CENTER, 0));
SerialAlignment textAlign = scene.getModel().getShowCFG() ?
LayoutFactory.SerialAlignment.LEFT_TOP :
LayoutFactory.SerialAlignment.CENTER;
middleWidget.setLayout(LayoutFactory.createVerticalFlowLayout(textAlign, 0));
middleWidget.setBackground(f.getColor());
middleWidget.setOpaque(true);
middleWidget.getActions().addAction(new DoubleClickAction(this));
middleWidget.setCheckClipping(true);
dummyTop = new Widget(scene);
dummyTop.setMinimumSize(new Dimension(Figure.INSET / 2, 1));
int extraTopHeight =
getFigure().getDiagram().isCFG() && getFigure().hasNamedInputSlot() ?
Figure.TOP_CFG_HEIGHT : 0;
dummyTop.setMinimumSize(new Dimension(Figure.INSET / 2, 1 + extraTopHeight));
middleWidget.addChild(dummyTop);
String[] strings = figure.getLines();
@ -132,10 +139,13 @@ public class FigureWidget extends Widget implements Properties.Provider, PopupMe
}
Widget dummyBottom = new Widget(scene);
dummyBottom.setMinimumSize(new Dimension(Figure.INSET / 2, 1));
int extraBottomHeight =
getFigure().getDiagram().isCFG() && getFigure().hasNamedOutputSlot() ?
Figure.BOTTOM_CFG_HEIGHT : 0;
dummyBottom.setMinimumSize(new Dimension(Figure.INSET / 2, 1 + extraBottomHeight));
middleWidget.addChild(dummyBottom);
middleWidget.setPreferredBounds(new Rectangle(0, Figure.SLOT_WIDTH - Figure.OVERLAPPING, f.getWidth(), f.getHeight()));
middleWidget.setPreferredBounds(new Rectangle(0, Figure.getVerticalOffset(), f.getWidth(), f.getHeight()));
this.addChild(middleWidget);
// Initialize node for property sheet

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -26,7 +26,6 @@ package com.sun.hotspot.igv.view.widgets;
import com.sun.hotspot.igv.graph.Figure;
import com.sun.hotspot.igv.graph.InputSlot;
import com.sun.hotspot.igv.view.DiagramScene;
import java.awt.Point;
import java.util.List;
import org.netbeans.api.visual.widget.Widget;
@ -41,12 +40,6 @@ public class InputSlotWidget extends SlotWidget {
public InputSlotWidget(InputSlot slot, DiagramScene scene, Widget parent, FigureWidget fw) {
super(slot, scene, parent, fw);
inputSlot = slot;
//init();
//getFigureWidget().getLeftWidget().addChild(this);
Point p = inputSlot.getRelativePosition();
p.x -= this.calculateClientArea().width / 2;
p.y += Figure.SLOT_START;
this.setPreferredLocation(p);
}
public InputSlot getInputSlot() {
@ -59,6 +52,12 @@ public class InputSlotWidget extends SlotWidget {
assert slots.contains(getSlot());
return calculateWidth(slots.size());
}
@Override
protected int yOffset() {
return getFigureWidget().getFigure().getDiagram().isCFG() ?
calculateClientArea().height - 1 : Figure.SLOT_START;
}
/*
protected Point calculateRelativeLocation() {
if (getFigureWidget().getBounds() == null) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -25,8 +25,8 @@ package com.sun.hotspot.igv.view.widgets;
import com.sun.hotspot.igv.graph.Connection;
import com.sun.hotspot.igv.graph.Figure;
import com.sun.hotspot.igv.graph.InputSlot;
import com.sun.hotspot.igv.graph.OutputSlot;
import com.sun.hotspot.igv.graph.Block;
import com.sun.hotspot.igv.util.StringUtils;
import com.sun.hotspot.igv.view.DiagramScene;
import java.awt.*;
@ -138,8 +138,10 @@ public class LineWidget extends Widget implements PopupMenuProvider {
public void select(Widget arg0, Point arg1, boolean arg2) {
Set<Figure> set = new HashSet<>();
for (Connection c : LineWidget.this.connections) {
set.add(c.getInputSlot().getFigure());
set.add(c.getOutputSlot().getFigure());
if (c.hasSlots()) {
set.add(scene.getWidget(c.getTo()));
set.add(scene.getWidget(c.getFrom()));
}
}
LineWidget.this.scene.setSelectedObjects(set);
}
@ -242,10 +244,12 @@ public class LineWidget extends Widget implements PopupMenuProvider {
Set<Object> highlightedObjects = new HashSet<>(scene.getHighlightedObjects());
Set<Object> highlightedObjectsChange = new HashSet<>();
for (Connection c : connections) {
highlightedObjectsChange.add(c.getInputSlot().getFigure());
highlightedObjectsChange.add(c.getInputSlot());
highlightedObjectsChange.add(c.getOutputSlot().getFigure());
highlightedObjectsChange.add(c.getOutputSlot());
if (c.hasSlots()) {
highlightedObjectsChange.add(c.getTo());
highlightedObjectsChange.add(c.getTo().getVertex());
highlightedObjectsChange.add(c.getFrom());
highlightedObjectsChange.add(c.getFrom().getVertex());
}
}
if(b) {
highlightedObjects.addAll(highlightedObjectsChange);
@ -312,14 +316,19 @@ public class LineWidget extends Widget implements PopupMenuProvider {
@Override
public JPopupMenu getPopupMenu(Widget widget, Point localLocation) {
JPopupMenu menu = new JPopupMenu();
menu.add(scene.createGotoAction(outputSlot.getFigure()));
menu.addSeparator();
for (Connection c : connections) {
InputSlot s = c.getInputSlot();
menu.add(scene.createGotoAction(s.getFigure()));
if (outputSlot == null) { // One-to-one block line.
assert (connections.size() == 1);
Connection c = connections.get(0);
menu.add(scene.createGotoAction((Block)c.getFromCluster()));
menu.addSeparator();
menu.add(scene.createGotoAction((Block)c.getToCluster()));
} else { // One-to-many figure line.
menu.add(scene.createGotoAction(outputSlot.getFigure()));
menu.addSeparator();
for (Connection c : connections) {
menu.add(scene.createGotoAction((Figure)c.getTo().getVertex()));
}
}
final LineWidget w = this;
menu.addPopupMenuListener(new PopupMenuListener() {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -26,7 +26,6 @@ package com.sun.hotspot.igv.view.widgets;
import com.sun.hotspot.igv.graph.Figure;
import com.sun.hotspot.igv.graph.OutputSlot;
import com.sun.hotspot.igv.view.DiagramScene;
import java.awt.Point;
import java.util.List;
import org.netbeans.api.visual.widget.Widget;
@ -41,10 +40,6 @@ public class OutputSlotWidget extends SlotWidget {
public OutputSlotWidget(OutputSlot slot, DiagramScene scene, Widget parent, FigureWidget fw) {
super(slot, scene, parent, fw);
outputSlot = slot;
Point p = outputSlot.getRelativePosition();
p.y += getSlot().getFigure().getHeight() - Figure.SLOT_START;
p.x -= this.calculateClientArea().width / 2;
this.setPreferredLocation(p);
}
public OutputSlot getOutputSlot() {
@ -58,4 +53,11 @@ public class OutputSlotWidget extends SlotWidget {
return calculateWidth(slots.size());
}
@Override
protected int yOffset() {
int overlap = getFigureWidget().getFigure().getDiagram().isCFG() ?
calculateClientArea().height : Figure.SLOT_START;
return getSlot().getFigure().getHeight() - overlap;
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -32,6 +32,7 @@ import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.util.HashSet;
@ -57,13 +58,16 @@ public abstract class SlotWidget extends Widget implements DoubleClickHandler {
this.diagramScene = scene;
this.slot = slot;
figureWidget = fw;
if (!slot.getSource().getSourceNodes().isEmpty()) {
if (slot.hasSourceNodes()) {
this.setToolTipText("<HTML>" + slot.getToolTipText() + "</HTML>");
}
this.setCheckClipping(true);
parent.addChild(this);
//this.setPreferredBounds(this.calculateClientArea());
Point p = slot.getRelativePosition();
p.x -= this.calculateClientArea().width / 2;
p.y += yOffset();
this.setPreferredLocation(p);
}
@Override
@ -92,7 +96,7 @@ public abstract class SlotWidget extends Widget implements DoubleClickHandler {
int w = this.getBounds().width;
int h = this.getBounds().height;
if (getSlot().getSource().getSourceNodes().size() > 0) {
if (getSlot().hasSourceNodes()) {
final int SMALLER = 0;
g.setColor(getSlot().getColor());
@ -109,7 +113,7 @@ public abstract class SlotWidget extends Widget implements DoubleClickHandler {
g.setStroke(new BasicStroke(1f));
}
if (getSlot().getShortName() != null && getSlot().getShortName().length() > 0) {
if (getSlot().shouldShowName()) {
g.setFont(font);
Rectangle2D r1 = g.getFontMetrics().getStringBounds(getSlot().getShortName(), g);
rectW = (int) r1.getWidth() + FONT_OFFSET * 2;
@ -123,14 +127,15 @@ public abstract class SlotWidget extends Widget implements DoubleClickHandler {
}
g.drawRect(w / 2 - rectW / 2, 0, rectW - 1, s - 1);
if (getSlot().getShortName() != null && getSlot().getShortName().length() > 0 && getScene().getZoomFactor() >= TEXT_ZOOM_FACTOR) {
if (getSlot().shouldShowName() && 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()));
}
} else {
if (this.getSlot().getConnections().isEmpty()) {
if (this.getSlot().getConnections().isEmpty() &&
!getFigureWidget().getFigure().getDiagram().isCFG()) {
if (this.getState().isHighlighted()) {
g.setColor(Color.BLUE);
} else {
@ -155,6 +160,8 @@ public abstract class SlotWidget extends Widget implements DoubleClickHandler {
protected abstract int calculateSlotWidth();
protected abstract int yOffset();
protected int calculateWidth(int count) {
return getFigureWidget().getFigure().getWidth() / count;
}

@ -1,6 +1,8 @@
CTL_EditorAction=Open Editor Window
CTL_NextDiagramAction=Show next graph
CTL_EnableSeaLayoutAction=Enable sea-of-nodes layout
CTL_EnableBlockLayoutAction=Enable block layout
CTL_EnableCFGLayoutAction=Enable control-flow graph layout
CTL_NodeFindAction=Find
CTL_PrevDiagramAction=Show previous graph
CTL_ExportAction=Export current graph...

Binary file not shown.

After

(image error) Size: 1.7 KiB

Binary file not shown.

After

(image error) Size: 1.6 KiB

Binary file not shown.

After

(image error) Size: 1.6 KiB

@ -17,7 +17,9 @@
<file name="com-sun-hotspot-igv-view-actions-ZoomOutAction.instance"><attr name="position" intvalue="2001"/></file>
<file name="com-sun-hotspot-igv-view-actions-OverviewAction.instance"><attr name="position" intvalue="2001"/></file>
<file name="com-sun-hotspot-igv-view-actions-PredSuccAction.instance"><attr name="position" intvalue="2001"/></file>
<file name="com-sun-hotspot-igv-view-actions-EnableSeaLayoutAction.instance"><attr name="position" intvalue="2001"/></file>
<file name="com-sun-hotspot-igv-view-actions-EnableBlockLayoutAction.instance"><attr name="position" intvalue="2001"/></file>
<file name="com-sun-hotspot-igv-view-actions-EnableCFGLayoutAction.instance"><attr name="position" intvalue="2001"/></file>
</folder>
</folder>
<folder name="Menu">
@ -80,6 +82,11 @@
<attr name="position" intvalue="0"/>
<file name="com-sun-hotspot-igv-view-NodeQuickSearch.instance"/>
</folder>
<folder name="Blocks">
<attr name="command" stringvalue="n"/>
<attr name="position" intvalue="1"/>
<file name="com-sun-hotspot-igv-view-BlockQuickSearch.instance"/>
</folder>
<file name="Projects_hidden"/>
</folder>