8302738: IGV: refine 'Simplify graph' filter

Reviewed-by: tholenstein, chagedorn
(cherry picked from commit 345669c29d)
This commit is contained in:
Roberto Castañeda Lozano
2023-03-31 12:03:47 +00:00
committed by Vitaly Provodin
parent 99829d13a0
commit 0dbe5c52e5
37 changed files with 674 additions and 344 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2023, 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.filter;
import com.sun.hotspot.igv.data.ChangedEvent;
import com.sun.hotspot.igv.data.Properties;
import com.sun.hotspot.igv.graph.Figure;
import org.openide.cookies.OpenCookie;
/**
@@ -60,4 +61,14 @@ public abstract class AbstractFilter implements Filter {
protected void fireChangedEvent() {
changedEvent.fire();
}
protected static String getFirstMatchingProperty(Figure figure, String[] propertyNames) {
for (String propertyName : propertyNames) {
String s = figure.getProperties().resolveString(propertyName);
if (s != null && !s.isEmpty()) {
return s;
}
}
return null;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, 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,13 +23,9 @@
*/
package com.sun.hotspot.igv.filter;
import com.sun.hotspot.igv.data.Properties;
import com.sun.hotspot.igv.data.Properties.PropertyMatcher;
import com.sun.hotspot.igv.graph.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
*
@@ -53,12 +49,11 @@ public class CombineFilter extends AbstractFilter {
@Override
public void apply(Diagram diagram) {
Properties.PropertySelector<Figure> selector = new Properties.PropertySelector<>(diagram.getFigures());
for (CombineRule r : rules) {
List<Figure> list = selector.selectMultiple(r.getFirstMatcher());
Set<Figure> figuresToRemove = new HashSet<>();
for (Figure f : list) {
List<Figure> first = r.getFirstSelector().selected(diagram);
List<Figure> second = r.getSecondSelector().selected(diagram);
for (Figure f : first) {
List<Figure> successors = new ArrayList<>(f.getSuccessors());
if (r.isReversed()) {
@@ -75,8 +70,8 @@ public class CombineFilter extends AbstractFilter {
}
slot.getSource().addSourceNode(f.getInputNode());
if (r.getShortProperty() != null) {
String s = f.getProperties().get(r.getShortProperty());
if (r.getPropertyNames() != null && r.getPropertyNames().length > 0) {
String s = r.getFirstMatchingProperty(f);
if (s != null && s.length() > 0) {
slot.setShortName(s);
slot.setText(s);
@@ -103,15 +98,12 @@ public class CombineFilter extends AbstractFilter {
newConn.setStyle(c.getStyle());
}
}
figuresToRemove.add(f);
}
} else {
for (Figure succ : successors) {
if (succ.getPredecessors().size() == 1 && succ.getInputSlots().size() == 1) {
if (succ.getProperties().selectSingle(r.getSecondMatcher()) != null && succ.getOutputSlots().size() == 1) {
if (succ.getPredecessors().size() == 1) {
if (second.contains(succ) && succ.getOutputSlots().size() <= 1) {
OutputSlot oldSlot = null;
for (OutputSlot s : f.getOutputSlots()) {
@@ -124,15 +116,19 @@ public class CombineFilter extends AbstractFilter {
assert oldSlot != null;
OutputSlot nextSlot = succ.getOutputSlots().get(0);
OutputSlot nextSlot = null;
if (succ.getOutputSlots().size() == 1) {
nextSlot = succ.getOutputSlots().get(0);
}
int pos = 0;
if (succ.getProperties().get("con") != null) {
pos = Integer.parseInt(succ.getProperties().get("con"));
}
OutputSlot slot = f.createOutputSlot(pos);
slot.getSource().addSourceNode(succ.getInputNode());
if (r.getShortProperty() != null) {
String s = succ.getProperties().get(r.getShortProperty());
if (r.getPropertyNames() != null && r.getPropertyNames().length > 0) {
String s = r.getFirstMatchingProperty(succ);
if (s != null && s.length() > 0) {
slot.setShortName(s);
slot.setText(s);
@@ -155,14 +151,15 @@ public class CombineFilter extends AbstractFilter {
}
}
}
for (FigureConnection c : nextSlot.getConnections()) {
FigureConnection newConn = diagram.createConnection(c.getInputSlot(), slot, c.getLabel());
newConn.setColor(c.getColor());
newConn.setStyle(c.getStyle());
if (nextSlot != null) {
for (FigureConnection c : nextSlot.getConnections()) {
FigureConnection newConn = diagram.createConnection(c.getInputSlot(), slot, c.getLabel());
newConn.setColor(c.getColor());
newConn.setStyle(c.getStyle());
}
}
figuresToRemove.add(succ);
diagram.removeFigure(succ);
if (oldSlot.getConnections().size() == 0) {
f.removeSlot(oldSlot);
@@ -172,8 +169,6 @@ public class CombineFilter extends AbstractFilter {
}
}
}
diagram.removeAllFigures(figuresToRemove);
}
}
@@ -183,41 +178,36 @@ public class CombineFilter extends AbstractFilter {
public static class CombineRule {
private PropertyMatcher first;
private PropertyMatcher second;
private Selector first;
private Selector second;
private boolean reversed;
private String shortProperty;
private String[] propertyNames;
public CombineRule(PropertyMatcher first, PropertyMatcher second) {
this(first, second, false);
}
public CombineRule(PropertyMatcher first, PropertyMatcher second, boolean reversed) {
this(first, second, reversed, null);
}
public CombineRule(PropertyMatcher first, PropertyMatcher second, boolean reversed, String shortProperty) {
public CombineRule(Selector first, Selector second, boolean reversed, String[] propertyNames) {
this.first = first;
this.second = second;
this.reversed = reversed;
this.shortProperty = shortProperty;
this.propertyNames = propertyNames;
}
public boolean isReversed() {
return reversed;
}
public PropertyMatcher getFirstMatcher() {
public Selector getFirstSelector() {
return first;
}
public PropertyMatcher getSecondMatcher() {
public Selector getSecondSelector() {
return second;
}
public String getShortProperty() {
return shortProperty;
public String[] getPropertyNames() {
return propertyNames;
}
public String getFirstMatchingProperty(Figure figure) {
return AbstractFilter.getFirstMatchingProperty(figure, propertyNames);
}
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2023, 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.Figure;
import com.sun.hotspot.igv.graph.Selector;
import java.util.function.UnaryOperator;
import java.util.List;
public class EditPropertyFilter extends AbstractFilter {
private String name;
private Selector selector;
private final String inputPropertyName;
private final String outputPropertyName;
private final UnaryOperator<String> editFunction;
public EditPropertyFilter(String name, Selector selector,
String inputPropertyName, String outputPropertyName,
UnaryOperator<String> editFunction) {
this.name = name;
this.selector = selector;
this.inputPropertyName = inputPropertyName;
this.outputPropertyName = outputPropertyName;
this.editFunction = editFunction;
}
@Override
public String getName() {
return name;
}
@Override
public void apply(Diagram diagram) {
List<Figure> list = selector.selected(diagram);
for (Figure f : list) {
String inputVal = f.getProperties().get(inputPropertyName);
String outputVal = editFunction.apply(inputVal);
f.getProperties().setProperty(outputPropertyName, outputVal);
}
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 2023, 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.*;
import java.util.ArrayList;
import java.util.List;
public class RemoveEmptySlotsFilter extends AbstractFilter {
private String name;
private Selector selector;
public RemoveEmptySlotsFilter(String name, Selector selector) {
this.name = name;
this.selector = selector;
}
@Override
public String getName() {
return name;
}
@Override
public void apply(Diagram diagram) {
List<Figure> list = selector.selected(diagram);
for (Figure f : list) {
List<InputSlot> empty = new ArrayList<>();
for (InputSlot is : f.getInputSlots()) {
if (is.getConnections().isEmpty()) {
empty.add(is);
}
}
for (InputSlot is : empty) {
f.removeSlot(is);
}
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, 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
@@ -48,53 +48,17 @@ public class RemoveInputsFilter extends AbstractFilter {
@Override
public void apply(Diagram diagram) {
for (RemoveInputsRule r : rules) {
List<Figure> list = r.getSelector().selected(diagram);
List<Figure> list = r.getNodeSelector().selected(diagram);
List<Figure> slotList = r.getSlotSelector().selected(diagram);
for (Figure f : list) {
int z = 0;
List<InputSlot> last = new ArrayList<>();
for (InputSlot is : f.getInputSlots()) {
if (z >= r.getStartingIndex() && z <= r.getEndIndex() && is.getConnections().size() > 0) {
StringBuilder sb = new StringBuilder();
List<FigureConnection> conns = is.getConnections();
for (int i = 0; i < conns.size(); i++) {
FigureConnection c = conns.get(i);
OutputSlot os = c.getOutputSlot();
Figure pred = os.getFigure();
if (i != 0) {
sb.append("<BR>");
}
sb.append(pred.getLines()[0]);
List<FigureConnection> conns = is.getConnections();
if (conns.size() == 1) {
Figure i = conns.get(0).getOutputSlot().getFigure();
if (slotList.contains(i)) {
is.removeAllConnections();
}
is.removeAllConnections();
is.setShortName("X");
is.setText(sb.toString());
last.add(is);
} else {
last.clear();
}
z++;
}
if (last.size() > 3) {
InputSlot first = last.get(0);
first.setShortName("XX");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < last.size(); i++) {
InputSlot is2 = last.get(i);
if (i != 0) {
sb.append("<BR>");
}
sb.append(is2.getText());
}
first.setText(sb.toString());
for (int i = 1; i < last.size(); i++) {
f.removeSlot(last.get(i));
}
}
}
@@ -107,34 +71,20 @@ public class RemoveInputsFilter extends AbstractFilter {
public static class RemoveInputsRule {
private Selector selector;
private int startingIndex;
private int endIndex;
private Selector nodeSelector;
private Selector slotSelector;
public RemoveInputsRule(Selector selector) {
this(selector, 0);
public RemoveInputsRule(Selector nodeSelector, Selector slotSelector) {
this.nodeSelector = nodeSelector;
this.slotSelector = slotSelector;
}
public RemoveInputsRule(Selector selector, int startIndex) {
this(selector, startIndex, Integer.MAX_VALUE);
public Selector getNodeSelector() {
return nodeSelector;
}
public RemoveInputsRule(Selector selector, int startIndex, int endIndex) {
this.startingIndex = startIndex;
this.endIndex = endIndex;
this.selector = selector;
}
public int getStartingIndex() {
return startingIndex;
}
public int getEndIndex() {
return endIndex;
}
public Selector getSelector() {
return selector;
public Selector getSlotSelector() {
return slotSelector;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, 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,12 +34,12 @@ public class SplitFilter extends AbstractFilter {
private String name;
private Selector selector;
private String propertyName;
private String[] propertyNames;
public SplitFilter(String name, Selector selector, String propertyName) {
public SplitFilter(String name, Selector selector, String[] propertyNames) {
this.name = name;
this.selector = selector;
this.propertyName = propertyName;
this.propertyNames = propertyNames;
}
@Override
@@ -52,23 +52,7 @@ public class SplitFilter extends AbstractFilter {
List<Figure> list = selector.selected(d);
for (Figure f : list) {
for (InputSlot is : f.getInputSlots()) {
for (FigureConnection c : is.getConnections()) {
OutputSlot os = c.getOutputSlot();
if (f.getInputNode() != null) {
os.getSource().addSourceNode(f.getInputNode());
os.setColor(f.getColor());
}
String s = f.getProperties().resolveString(propertyName);
if (s != null) {
os.setShortName(s);
}
}
}
String s = AbstractFilter.getFirstMatchingProperty(f, propertyNames);
for (OutputSlot os : f.getOutputSlots()) {
for (FigureConnection c : os.getConnections()) {
InputSlot is = c.getInputSlot();
@@ -76,8 +60,6 @@ public class SplitFilter extends AbstractFilter {
is.getSource().addSourceNode(f.getInputNode());
is.setColor(f.getColor());
}
String s = f.getProperties().resolveString(propertyName);
if (s != null) {
is.setShortName(s);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, 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
@@ -21,61 +21,122 @@
* questions.
*
*/
/**
*
* @author Thomas Wuerthinger
*/
function colorize(property, regexp, color) {
var f = new ColorFilter("");
f.addRule(new ColorFilter.ColorRule(new MatcherSelector(new Properties.RegexpPropertyMatcher(property, regexp)), color));
f.apply(graph);
// Split a string by whitespace, collapsing repeated ones.
function split_string(s) {
return s.split(/(\s+)/).filter(function(e) {return e.trim().length > 0;});
}
// Select the node union in a list of selectors.
function or(selectors) {
return new OrSelector(selectors);
}
// Select the node intersection in a list of selectors.
function and(selectors) {
return new AndSelector(selectors);
}
// Select the nodes that are not selected by a given selector.
function not(selector) {
return new InvertSelector(selector);
}
// Select the nodes that succeed those given by a selector.
function successorOf(selector) {
return new SuccessorSelector(selector);
}
// Select the blocks where at least one node is selected by the given selector.
function hasAnyNode(selector) {
return new AnySelector(selector);
}
// Select the nodes whose given property matches a given regular expression.
function matches(property, regexp) {
return new MatcherSelector(new Properties.RegexpPropertyMatcher(property, regexp));
}
// Color the selected nodes.
function colorize(selector, color) {
var f = new ColorFilter("");
f.addRule(new ColorFilter.ColorRule(selector, color));
f.apply(graph);
}
// Invisible connection style (used to hide edges).
invisibleConnection = Connection.ConnectionStyle.INVISIBLE;
// Apply a given style (e.g. invisible) and color to the out edges of the
// selected nodes.
function styleOutputConnections(selector, color, style) {
var f = new ConnectionFilter("");
f.addRule(new ConnectionFilter.ConnectionStyleRule(selector, color, style));
f.apply(graph);
}
// Display a warning with the contents of a given property ('propertyToShow') in
// the nodes whose given property ('propertyToMatch') matches a regular
// expression.
function warn(propertyToMatch, regexp, propertyToShow) {
var f = new WarningFilter("", "[" + propertyToShow + "]");
f.addRule(new WarningFilter.WarningRule(new MatcherSelector(new Properties.RegexpPropertyMatcher(propertyToMatch, regexp))));
f.addRule(new WarningFilter.WarningRule(matches(propertyToMatch, regexp)));
f.apply(graph);
}
function remove(property, regexp) {
// Remove edges with the same source and destination node.
function removeSelfLoops() {
var f = new RemoveSelfLoopsFilter("");
f.apply(graph);
}
// Remove the selected nodes.
function remove(selector) {
var f = new RemoveFilter("");
f.addRule(new RemoveFilter.RemoveRule(new MatcherSelector(new Properties.RegexpPropertyMatcher(property, regexp))));
f.addRule(new RemoveFilter.RemoveRule(selector));
f.apply(graph);
}
// Remove the selected nodes and nodes that become orphan after the removal.
function removeIncludingOrphans(property, regexp) {
var f = new RemoveFilter("");
f.addRule(new RemoveFilter.RemoveRule(new MatcherSelector(new Properties.RegexpPropertyMatcher(property, regexp)), true));
f.apply(graph);
}
function split(property, regexp, propertyName) {
if (propertyName == undefined) {
propertyName = graph.getNodeText();
}
var f = new SplitFilter("", new MatcherSelector(new Properties.RegexpPropertyMatcher(property, regexp)), propertyName);
f.apply(graph);
}
function removeInputs(property, regexp, from, to) {
var f = new RemoveInputsFilter("");
if(from == undefined && to == undefined) {
f.addRule(new RemoveInputsFilter.RemoveInputsRule(new MatcherSelector(new Properties.RegexpPropertyMatcher(property, regexp))));
} else if(to == undefined) {
f.addRule(new RemoveInputsFilter.RemoveInputsRule(new MatcherSelector(new Properties.RegexpPropertyMatcher(property, regexp)), from));
} else {
f.addRule(new RemoveInputsFilter.RemoveInputsRule(new MatcherSelector(new Properties.RegexpPropertyMatcher(property, regexp)), from, to));
// Inline the selected nodes into their successors and display the first found
// property in the given property list in the resulting input slots.
function split(selector, propertyNames) {
if (propertyNames == undefined) {
propertyNames = [];
}
new SplitFilter("", selector, propertyNames).apply(graph);
}
// Combine the selected (second) nodes into their selected (first) predecessors
// and display the first found property in the given property list in the
// resulting output slots.
function combine(first, second, propertyNames) {
if (propertyNames == undefined) {
propertyNames = [];
}
var f = new CombineFilter("");
f.addRule(new CombineFilter.CombineRule(first, second, false, propertyNames));
f.apply(graph);
}
// Remove (input and/or output) slots without connecting edges.
function removeUnconnectedSlots(inputs, outputs) {
var f = new UnconnectedSlotFilter(inputs, outputs);
f.apply(graph);
}
// Color nodes using a gradient based on the given property and min/max values.
function colorizeGradient(property, min, max) {
var f = new GradientColorFilter();
f.setPropertyName(property);
@@ -84,6 +145,8 @@ function colorizeGradient(property, min, max) {
f.apply(graph);
}
// Color nodes using a gradient based on the given property, min/max values, and
// mode ("LINEAR" or "LOGARITHMIC").
function colorizeGradientWithMode(property, min, max, mode) {
var f = new GradientColorFilter();
f.setPropertyName(property);
@@ -93,6 +156,9 @@ function colorizeGradientWithMode(property, min, max, mode) {
f.apply(graph);
}
// Color nodes using a custom gradient based on the given property, min/max
// values, mode ("LINEAR" or "LOGARITHMIC"), list of colors, list of fractions,
// and number of shades.
function colorizeGradientCustom(property, min, max, mode, colors, fractions, nshades) {
var f = new GradientColorFilter();
f.setPropertyName(property);
@@ -105,6 +171,7 @@ function colorizeGradientCustom(property, min, max, mode, colors, fractions, nsh
f.apply(graph);
}
// Pre-defined colors for coloring filters.
var black = Color.black;
var blue = Color.blue;
var cyan = Color.cyan;
@@ -118,3 +185,38 @@ var pink = Color.pink
var red = Color.red;
var yellow = Color.yellow;
var white = Color.white;
// Update the value of the given property in the selected nodes according to a
// function that takes as input the old property value and returns the new
// property value.
function editSameProperty(selector, propertyName, editFunction) {
var f = new EditPropertyFilter("", selector, propertyName, propertyName, editFunction);
f.apply(graph);
}
// Update the value of the given property ('outputPropertyName') in the selected
// nodes according to a function that takes as input the value of a possibly
// different property ('inputPropertyName') and returns the new property value.
function editProperty(selector, inputPropertyName, outputPropertyName, editFunction) {
var f = new EditPropertyFilter("", selector, inputPropertyName, outputPropertyName, editFunction);
f.apply(graph);
}
// Remove edges that go from the selected slots into the selected nodes.
function removeInputs(nodeSelector, slotSelector) {
var f = new RemoveInputsFilter("");
f.addRule(new RemoveInputsFilter.RemoveInputsRule(nodeSelector, slotSelector));
f.apply(graph);
}
// Remove empty slots in the selected nodes, condensing all inputs as a result.
function removeEmptySlots(selector) {
new RemoveEmptySlotsFilter("", selector).apply(graph);
}
// Remove the selected block.
function removeBlock(selector) {
var f = new RemoveBlockFilter("");
f.addRule(new RemoveBlockFilter.RemoveBlockRule(selector));
f.apply(graph);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, 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,23 +32,24 @@ import java.util.List;
*/
public class AndSelector implements Selector {
private Selector selector1;
private Selector selector2;
private Selector[] selectors;
public AndSelector(Selector s1, Selector s2) {
this.selector1 = s1;
this.selector2 = s2;
public AndSelector(Selector[] selectors) {
this.selectors = selectors;
}
@Override
public List<Figure> selected(Diagram d) {
List<Figure> l1 = selector1.selected(d);
List<Figure> l2 = selector2.selected(d);
List<Figure> result = new ArrayList<>();
for (Figure f : l2) {
if (l1.contains(f)) {
result.add(f);
List<Figure> result = d.getFigures();
for (Selector s : selectors) {
List<Figure> selected = s.selected(d);
List<Figure> newResult = new ArrayList<>();
for (Figure f : result) {
if (selected.contains(f)) {
newResult.add(f);
}
}
result = newResult;
}
return result;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, 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,6 +113,14 @@ public class Diagram {
}
}
for (Figure f : figures) {
int i = 0;
for (InputSlot inputSlot : f.getInputSlots()) {
inputSlot.setOriginalIndex(i);
i++;
}
}
for (InputBlockEdge e : graph.getBlockEdges()) {
Block p = getBlock(e.getFrom());
Block s = getBlock(e.getTo());

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, 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
@@ -41,6 +41,7 @@ public class Figure extends Properties.Entity implements Vertex {
public static final int TOP_CFG_HEIGHT = 7;
public static final int BOTTOM_CFG_HEIGHT = 6;
public static final int WARNING_WIDTH = 16;
public static final double BOLD_LINE_FACTOR = 1.06;
protected List<InputSlot> inputSlots;
protected List<OutputSlot> outputSlots;
private final InputNode inputNode;
@@ -71,6 +72,9 @@ public class Figure extends Properties.Entity implements Vertex {
if (hasInputList() && lines > 1) {
lines++;
}
if (getProperties().get("extra_label") != null) {
lines++;
}
heightCash = lines * metrics.getHeight() + INSET;
if (diagram.isCFG()) {
if (hasNamedInputSlot()) {
@@ -120,7 +124,7 @@ public class Figure extends Properties.Entity implements Vertex {
max = cur;
}
}
widthCash = max + INSET;
widthCash = (int)(max * BOLD_LINE_FACTOR) + INSET;
if (getWarning() != null) {
widthCash += WARNING_WIDTH;
}
@@ -164,7 +168,7 @@ public class Figure extends Properties.Entity implements Vertex {
}
public boolean hasInputList() {
return diagram.isCFG() && !getPredecessors().isEmpty();
return diagram.isCFG() && !getInputSlots().isEmpty();
}
public void setBlock(Block block) {
@@ -320,8 +324,31 @@ public class Figure extends Properties.Entity implements Vertex {
if (hasInputList()) {
String inputList = "";
List<String> inputs = new ArrayList<>(getPredecessors().size());
for (Figure p : getPredecessors()) {
inputs.add(p.getProperties().resolveString(diagram.getTinyNodeText()));
for (InputSlot is : getInputSlots()) {
String inputLabel = null;
if (is.getConnections().isEmpty()) {
if (is.hasSourceNodes() && is.shouldShowName()) {
inputLabel = "[" + is.getShortName() + "]";
} else {
inputLabel = "_";
}
} else {
OutputSlot os = is.getConnections().get(0).getOutputSlot();
Figure f = os.getFigure();
String nodeTinyLabel = f.getProperties().resolveString(diagram.getTinyNodeText());
if (os.hasSourceNodes() && os.shouldShowName()) {
nodeTinyLabel += ":" + os.getShortName();
}
inputLabel = nodeTinyLabel;
}
assert(inputLabel != null);
int gapSize = is.gapSize();
if (gapSize == 1) {
inputs.add("_");
} else if (gapSize > 1) {
inputs.add("");
}
inputs.add(inputLabel);
}
inputList += String.join(" ", inputs);
if (result.size() == 1) {
@@ -333,6 +360,11 @@ public class Figure extends Properties.Entity implements Vertex {
}
}
String extraLabel = getProperties().get("extra_label");
if (extraLabel != null) {
result.add(extraLabel);
}
lines = result.toArray(new String[0]);
// Set the "label" property of the input node, so that by default
// search is done on the node label (without line breaks). See also

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, 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
@@ -106,7 +106,7 @@ public class FigureConnection implements Connection {
builder.append("");
builder.append(getInputSlot().getFigure().getProperties().resolveString(shortNodeText));
builder.append(" [")
.append(getInputSlot().getPosition())
.append(getInputSlot().getOriginalIndex())
.append("]");
return builder.toString();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, 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 java.util.List;
*/
public class InputSlot extends Slot {
private int originalIndex;
protected InputSlot(Figure figure, int wantedIndex) {
super(figure, wantedIndex);
this.originalIndex = -1;
}
@Override
@@ -47,13 +50,34 @@ public class InputSlot extends Slot {
InputSlot s = inputSlots.remove(position);
inputSlots.add(position, s);
}
public int getOriginalIndex() {
return originalIndex;
}
public void setOriginalIndex(int originalIndex) {
this.originalIndex = originalIndex;
}
public int gapSize() {
int index = getPosition();
int originalIndex = getOriginalIndex();
InputSlot prevSlot = index > 0 ? getFigure().getInputSlots().get(index - 1) : null;
int prevOriginalIndex = index > 0 ? prevSlot.getOriginalIndex() : -1;
return originalIndex - prevOriginalIndex - 1;
}
@Override
public Point getRelativePosition() {
int gap = getFigure().getWidth() - Figure.getSlotsWidth(getFigure().getInputSlots());
double gapRatio = (double)gap / (double)(getFigure().getInputSlots().size() + 1);
int gapAmount = (int)((getPosition() + 1)*gapRatio);
return new Point(gapAmount + Figure.getSlotsWidth(Figure.getAllBefore(getFigure().getInputSlots(), this)) + getWidth()/2, -Figure.SLOT_START);
//return new Point((getFigure().getWidth() / (getFigure().getInputSlots().size() * 2)) * (getPosition() * 2 + 1), -Figure.SLOT_START);
}
@Override
public String getToolTipText() {
return super.getToolTipText() + " [" + originalIndex + "]";
}
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, 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.util.ArrayList;
import java.util.List;
/**
@@ -31,27 +32,22 @@ import java.util.List;
*/
public class OrSelector implements Selector {
private Selector selector1;
private Selector selector2;
private Selector[] selectors;
/** Creates a new instance of OrSelector */
public OrSelector(Selector s1, Selector s2) {
this.selector1 = s1;
this.selector2 = s2;
public OrSelector(Selector[] selectors) {
this.selectors = selectors;
}
@Override
public List<Figure> selected(Diagram d) {
List<Figure> l1 = selector1.selected(d);
List<Figure> l2 = selector2.selected(d);
for (Figure f : l2) {
if (!l1.contains(f)) {
l1.add(f);
List<Figure> result = new ArrayList<>();
for (Selector s : selectors) {
for (Figure f : s.selected(d)) {
if (!result.contains(f)) {
result.add(f);
}
}
}
return l1;
return result;
}
}

View File

@@ -46,5 +46,15 @@ Alternatively the output can be sent to a file using
with unique names being generated by adding a number onto the provided file
name.
## Defining Custom Filters
IGV has a powerful filter mechanism with which nodes and blocks can be colored,
hidden, updated, etc. according to user-defined rules. Filters are programmed in
JavaScript using a set of predefined primitives and auxiliary functions. For
more information, see the documentation in
`Filter/src/main/resources/com/sun/hotspot/igv/filter/helper.js` and the default
filters in
`ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters`.
More information about the tool is available at
https://wiki.openjdk.org/display/HotSpot/IdealGraphVisualizer.

View File

@@ -10,16 +10,16 @@ var otherEdgeColor = java.awt.Color.decode("#dfc025");
var dataEdgeColor = java.awt.Color.decode("#3178c2");
var memoryEdgeColor = java.awt.Color.decode("#828200");
colorize("category", "data", dataNodeColor);
colorize("category", "memory", memoryNodeColor);
colorize("category", "mixed", mixedNodeColor);
colorize("category", "control", controlNodeColor);
colorize("category", "other", otherNodeColor);
colorize(matches("category", "data"), dataNodeColor);
colorize(matches("category", "memory"), memoryNodeColor);
colorize(matches("category", "mixed"), mixedNodeColor);
colorize(matches("category", "control"), controlNodeColor);
colorize(matches("category", "other"), otherNodeColor);
var f = new ColorFilter("Line Style filter");
f.addRule(new ColorFilter.ColorRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "data")), null, dataEdgeColor, null));
f.addRule(new ColorFilter.ColorRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "memory")), null, memoryEdgeColor, null));
f.addRule(new ColorFilter.ColorRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "mixed")), null, mixedEdgeColor, null));
f.addRule(new ColorFilter.ColorRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "control")), null, controlEdgeColor, null));
f.addRule(new ColorFilter.ColorRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "other")), null, otherEdgeColor, null));
f.addRule(new ColorFilter.ColorRule(matches("category", "data"), null, dataEdgeColor, null));
f.addRule(new ColorFilter.ColorRule(matches("category", "memory"), null, memoryEdgeColor, null));
f.addRule(new ColorFilter.ColorRule(matches("category", "mixed"), null, mixedEdgeColor, null));
f.addRule(new ColorFilter.ColorRule(matches("category", "control"), null, controlEdgeColor, null));
f.addRule(new ColorFilter.ColorRule(matches("category", "other"), null, otherEdgeColor, null));
f.apply(graph);

View File

@@ -0,0 +1,66 @@
// Condense the graph without information loss and make the structure of the
// intermediate representation more explicit. This filter is most effective in
// combination with "Simplify graph".
// Pretty-print Bool nodes to be shown as output slots.
function replaceComparisonWithSign(dump_spec) {
var comparison = dump_spec.replace('[','').replace(']','')
switch (comparison) {
case "eq": return "=";
case "gt": return ">";
case "lt": return "<";
case "ne": return "≠";
case "le": return "≤";
case "ge": return "≥";
default: return comparison;
}
}
editSameProperty(matches("name", "Bool"), "dump_spec", replaceComparisonWithSign);
// Add a more informative text for null-pointer input slots.
editSameProperty(and([matches("name", "ConP|ConN"), matches("dump_spec", "#.*NULL")]),
"short_name",
function(t) {return "null";});
// Pretty-print CatchProj nodes.
function catchProjShortText(con) {
switch (con) {
case "0": return "F"; // fall-through
case "1": return "T"; // throw
default: return "?";
}
}
editProperty(matches("name", "CatchProj"), "con", "short_name", catchProjShortText);
// Add short text to inlined Mach data parameters.
editProperty(and([matches("name", "MachProj"),
matches("category", "data"),
successorOf(matches("name", "Start"))]),
"dump_spec", "short_name",
function(dump_spec) {return dump_spec;});
// Condense inputs in all nodes.
var anyNode = matches("name", ".*");
removeEmptySlots(anyNode);
// Inline ("split") Parm and start MachProj nodes, except control ones.
split(and([matches("name", "Parm|MachProj"),
not(matches("category", "control")),
successorOf(matches("name", "Start"))]),
["[short_name]"]);
// Combine single-input nodes.
combine(anyNode, matches("name", "Proj|IfFalse|IfTrue|JProj|MachProj|JumpProj|CatchProj|Parm"));
combine(anyNode, matches("name", "SCMemProj"), ["SCM"]);
combine(matches("name", "SubTypeCheck|Cmp.*"), matches("name", "Bool"), ["[dump_spec]"]);
combine(anyNode, matches("name", "Decode(N|NarrowPtr|NKlass)"), ["DC"]);
combine(anyNode, matches("name", "Conv2B"), ["2B"]);
combine(anyNode, matches("name", "Conv[LFD]2I"), ["2I"]);
combine(anyNode, matches("name", "Conv[IFD]2L"), ["2L"]);
combine(anyNode, matches("name", "Conv[ILD]2F"), ["2F"]);
combine(anyNode, matches("name", "Conv[ILF]2D"), ["2D"]);
// Inline ("split") constant nodes.
split(matches("name", "MachTemp"), ["T"]);
split(matches("name", "ThreadLocal"), ["TL"]);
split(matches("name", "(Con[A-Z]?)|ConNKlass|(loadCon.*)"), ["[short_name]", "[name]"]);

View File

@@ -0,0 +1,46 @@
// This filter adds a new line to the label of selected nodes with custom
// information. This is achieved by adding a special property 'extra_label' to
// them with information extracted from other properties, typically 'dump_spec'.
// Add extra line to method calls with callee information.
function callJavaInfo(dump_spec, regularPos, trapPos) {
dump_components = split_string(dump_spec);
if (dump_components.length < (trapPos + 1)) {
return null;
}
var tm = /(uncommon_trap\(reason=\'(\w*)\')/.exec(dump_components[trapPos]);
if (tm == null || typeof tm[2] == 'undefined') {
return dump_components[regularPos];
}
return "trap: " + tm[2];
}
editProperty(matches("name", "CallStaticJava|CallDynamicJava|CallJava"), "dump_spec", "extra_label",
function(dump_spec) {return callJavaInfo(dump_spec, 2, 2);});
editProperty(matches("name", "CallStaticJavaDirect|CallDynamicJavaDirect"), "dump_spec", "extra_label",
function(dump_spec) {return callJavaInfo(dump_spec, 1, 3);});
function callLeafInfo(dump_spec, pos) {
dump_components = split_string(dump_spec);
if (dump_components.length < pos + 1) {
return null;
}
return dump_components[pos];
}
editProperty(matches("name", "CallLeaf|CallLeafNoFP"), "dump_spec", "extra_label",
function(dump_spec) {return callLeafInfo(dump_spec, 1);});
editProperty(matches("name", "CallLeafDirect|CallLeafDirectVector|CallLeafNoFPDirect"), "dump_spec", "extra_label",
function(dump_spec) {return callLeafInfo(dump_spec, 0);});
// Add extra line to exception creation nodes with the name of the exception.
function exceptionInfo(dump_spec) {
dump_spec2 = dump_spec.replace('#','')
dump_components = split_string(dump_spec2);
if (dump_components.length < 1) {
return null;
}
// dump_components[0] has a form like e.g. java/lang/NumberFormatException:NotNull,
// we want to return only the simple class name ("NumberFormatException").
simple_classname = dump_components[0].split("/").pop();
return simple_classname.split(":")[0];
}
editProperty(matches("name", "CreateEx|CreateException"), "dump_spec", "extra_label", exceptionInfo);

View File

@@ -1,3 +1 @@
var f = new RemoveFilter("Hide control subgraph");
f.addRule(new RemoveFilter.RemoveRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "control"))));
f.apply(graph);
remove(matches("category", "control"));

View File

@@ -1,5 +1 @@
var f = new ConnectionFilter("Hide control edges");
f.addRule(new ConnectionFilter.ConnectionStyleRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "control")),
white,
Connection.ConnectionStyle.INVISIBLE));
f.apply(graph);
styleOutputConnections(matches("category", "control"), white, invisibleConnection);

View File

@@ -1,3 +1 @@
var f = new RemoveFilter("Hide data subgraph");
f.addRule(new RemoveFilter.RemoveRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "data"))));
f.apply(graph);
remove(matches("category", "data"));

View File

@@ -1,5 +1 @@
var f = new ConnectionFilter("Hide data edges");
f.addRule(new ConnectionFilter.ConnectionStyleRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "data")),
white,
Connection.ConnectionStyle.INVISIBLE));
f.apply(graph);
styleOutputConnections(matches("category", "data"), white, invisibleConnection);

View File

@@ -1,18 +1,2 @@
// 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);
removeBlock(hasAnyNode(matches("name", "Rethrow|RethrowException")));

View File

@@ -1,3 +1 @@
var f = new RemoveFilter("Hide memory subgraph");
f.addRule(new RemoveFilter.RemoveRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "memory"))));
f.apply(graph);
remove(matches("category", "memory"));

View File

@@ -1,5 +1 @@
var f = new ConnectionFilter("Hide memory edges");
f.addRule(new ConnectionFilter.ConnectionStyleRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "memory")),
white,
Connection.ConnectionStyle.INVISIBLE));
f.apply(graph);
styleOutputConnections(matches("category", "memory"), white, invisibleConnection);

View File

@@ -1,3 +1 @@
var f = new RemoveFilter("Hide mixed subgraph");
f.addRule(new RemoveFilter.RemoveRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "mixed"))));
f.apply(graph);
remove(matches("category", "mixed"));

View File

@@ -1,5 +1 @@
var f = new ConnectionFilter("Hide mixed edges");
f.addRule(new ConnectionFilter.ConnectionStyleRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "mixed")),
white,
Connection.ConnectionStyle.INVISIBLE));
f.apply(graph);
styleOutputConnections(matches("category", "mixed"), white, invisibleConnection);

View File

@@ -1,3 +1 @@
var f = new RemoveFilter("Hide other subgraph");
f.addRule(new RemoveFilter.RemoveRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "other"))));
f.apply(graph);
remove(matches("category", "other"));

View File

@@ -1,5 +1 @@
var f = new ConnectionFilter("Hide other edges");
f.addRule(new ConnectionFilter.ConnectionStyleRule(new MatcherSelector(new Properties.StringPropertyMatcher("category", "other")),
white,
Connection.ConnectionStyle.INVISIBLE));
f.apply(graph);
styleOutputConnections(matches("category", "other"), white, invisibleConnection);

View File

@@ -1,13 +1,2 @@
// 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);
removeBlock(hasAnyNode(matches("name", "Root")));

View File

@@ -1,13 +1,2 @@
// 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);
removeBlock(hasAnyNode(matches("dump_spec", ".*uncommon_trap.*")));

View File

@@ -1,27 +1,6 @@
// Remove all nodes except control, mixed, and nodes of 'bottom' type that are
// successors of control nodes (typically 'Halt', 'Return', etc.).
var f = new RemoveFilter("Show only control flow");
f.addRule(
new RemoveFilter.RemoveRule(
new InvertSelector(
new OrSelector(
new MatcherSelector(
new Properties.RegexpPropertyMatcher("category", "control|mixed")
),
new AndSelector(
new SuccessorSelector(
new MatcherSelector(
new Properties.RegexpPropertyMatcher("type", "control")
)
),
new MatcherSelector(
new Properties.RegexpPropertyMatcher("type", "bottom")
)
)
)
),
false
)
);
f.apply(graph);
remove(not(or([matches("name", "Root"),
matches("category", "control|mixed"),
and([matches("type", "bottom"),
successorOf(matches("type", "control"))])])));

View File

@@ -0,0 +1,16 @@
// Hide graph elements that are typically (but not always) unnecessary to
// analyze the intermediate representation. This filter is most effective in
// combination with "Condense graph".
// Remove self-loops (typical for region-like control nodes).
removeSelfLoops();
// Hide secondary edges.
remove(matches("short_name", "FP|RA|IO|RP"));
// Remove back-edges to the Root node.
removeInputs(matches("name", "Root"), matches("name", ".*"));
// Remove top inputs from call-like nodes.
removeInputs(matches("name", "SafePoint|CallStaticJava|CallDynamicJava|CallJava|CallLeaf|CallRuntime|AbstractLock|CallLeafNoFP|Call|CallStaticJavaDirect|Halt|Rethrow|ShouldNotReachHere|RethrowException|Return|Ret|MergeMem|Initialize|MemBarAcquire|MemBarRelease|Unlock|Lock|Allocate|AllocateArray"),
and([matches("name", "Con"), matches("type", "top")]));

View File

@@ -1,19 +0,0 @@
// Hide secondary edges.
remove("dump_spec", "FramePtr|ReturnAdr|I_O");
removeInputs("name", "Root");
var f = new RemoveSelfLoopsFilter("Remove Self-Loops");
f.apply(graph);
removeInputs("name", "SafePoint|CallStaticJava|CallDynamicJava|CallJava|CallLeaf|CallRuntime|AbstractLock|CallLeafNoFP|Call|CallStaticJavaDirect", 5);
removeInputs("name", "Unlock|Lock", 7);
removeInputs("name", "Allocate", 7);
removeInputs("name", "AllocateArray", 9);
// Combine projection nodes.
var f = new CombineFilter("Combine Filter");
f.addRule(new CombineFilter.CombineRule(new Properties.RegexpPropertyMatcher("name", ".*"), new Properties.RegexpPropertyMatcher("name", "Proj|IfFalse|IfTrue|JProj|MachProj|JumpProj|CatchProj")));
f.addRule(new CombineFilter.CombineRule(new Properties.RegexpPropertyMatcher("name", "Cmp.*"), new Properties.RegexpPropertyMatcher("name", "Bool")));
f.apply(graph);
// Inline (split) constant nodes.
split("name", "BoxLock");
split("name", "(Con.*)|(loadCon.*)", "[dump_spec]");

View File

@@ -13,13 +13,21 @@
<attr name="enabled" boolvalue="true"/>
<attr name="after" stringvalue="Color by execution frequency"/>
</file>
<file name="Simplify graph.js" url="filters/structural.filter">
<file name="Show custom node info.js" url="filters/customNodeInfo.filter">
<attr name="enabled" boolvalue="true"/>
<attr name="after" stringvalue="Color by execution frequency"/>
</file>
<file name="Simplify graph.js" url="filters/simplifyGraph.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Show node warnings"/>
<attr name="after" stringvalue="Show custom node info"/>
</file>
<file name="Condense graph.js" url="filters/condenseGraph.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Simplify graph"/>
</file>
<file name="Hide data subgraph.js" url="filters/hideData.filter">
<attr name="enabled" boolvalue="false"/>
<attr name="after" stringvalue="Simplify graph"/>
<attr name="after" stringvalue="Condense graph"/>
</file>
<file name="Hide memory subgraph.js" url="filters/hideMemory.filter">
<attr name="enabled" boolvalue="false"/>

View File

@@ -106,7 +106,7 @@ public class FigureWidget extends Widget implements Properties.Provider, PopupMe
middleWidget.setBackground(f.getColor());
middleWidget.setOpaque(true);
middleWidget.getActions().addAction(new DoubleClickAction(this));
middleWidget.setCheckClipping(true);
middleWidget.setCheckClipping(false);
dummyTop = new Widget(scene);
int extraTopHeight =
@@ -137,6 +137,7 @@ public class FigureWidget extends Widget implements Properties.Provider, PopupMe
lw.setAlignment(LabelWidget.Alignment.CENTER);
lw.setVerticalAlignment(LabelWidget.VerticalAlignment.CENTER);
lw.setBorder(BorderFactory.createEmptyBorder());
lw.setCheckClipping(false);
}
if (getFigure().getWarning() != null) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, 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,9 +23,16 @@
*/
package com.sun.hotspot.igv.view.widgets;
import com.sun.hotspot.igv.graph.Diagram;
import com.sun.hotspot.igv.graph.Figure;
import com.sun.hotspot.igv.graph.FigureConnection;
import com.sun.hotspot.igv.graph.InputSlot;
import com.sun.hotspot.igv.view.DiagramScene;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.util.List;
import org.netbeans.api.visual.widget.Widget;
@@ -36,10 +43,12 @@ import org.netbeans.api.visual.widget.Widget;
public class InputSlotWidget extends SlotWidget {
private InputSlot inputSlot;
private DiagramScene scene;
public InputSlotWidget(InputSlot slot, DiagramScene scene, Widget parent, FigureWidget fw) {
super(slot, scene, parent, fw);
inputSlot = slot;
this.scene = scene;
}
public InputSlot getInputSlot() {
@@ -58,4 +67,65 @@ public class InputSlotWidget extends SlotWidget {
return getFigureWidget().getFigure().getDiagram().isCFG() ?
calculateClientArea().height - 1 : Figure.SLOT_START;
}
@Override
protected void paintWidget() {
super.paintWidget();
if (getScene().getZoomFactor() < TEXT_ZOOM_FACTOR) {
return;
}
// If there is a gap between the current slot and the previous one, and
// both are visible, draw a label in between signaling the gap.
int index = inputSlot.getPosition();
int originalIndex = inputSlot.getOriginalIndex();
InputSlot prevSlot = index > 0 ? inputSlot.getFigure().getInputSlots().get(index - 1) : null;
int prevOriginalIndex = index > 0 ? prevSlot.getOriginalIndex() : -1;
if (originalIndex > prevOriginalIndex + 1 &&
hasVisibleConnection(inputSlot) && hasVisibleConnection(prevSlot) &&
!scene.getModel().getShowCFG()) {
Graphics2D g = scene.getGraphics();
String label = "...";
g.setColor(Color.BLACK);
g.setFont(Diagram.SLOT_FONT.deriveFont(Font.BOLD));
Rectangle2D labelRect = new Canvas().getFontMetrics(Diagram.SLOT_FONT).getStringBounds(label, g);
int slotWidth = this.calculateClientArea().width;
int xStart = this.getBounds().x + (inputSlot.hasSourceNodes() ? 0 : (slotWidth / 2));
int prevXEnd;
if (index > 0) {
// Compute X coordinates of previous input slot comparing its
// calculateClientArea() with that of the current slot.
InputSlotWidget prevWidget = (InputSlotWidget)scene.findWidget(prevSlot);
int prevSlotWidth = prevWidget.calculateClientArea().width;
int xStartAbs = inputSlot.getRelativePosition().x - (slotWidth / 2);
int prevXStartAbs = prevSlot.getRelativePosition().x - (prevSlotWidth / 2);
int prevXStart = prevXStartAbs - xStartAbs;
prevXEnd = prevXStart + (prevSlot.hasSourceNodes() ? prevSlotWidth : (prevSlotWidth / 2));
} else {
// No previous input slot, just set its position to the left of
// the current one.
prevXEnd = xStart - (int) (labelRect.getWidth()) - 4;
}
int midX = (prevXEnd + xStart) / 2;
g.drawString(label, midX - (int)(labelRect.getWidth() / 2), 3);
}
}
// This method needs to be called at painting time, so that the right
// FigureWidget::isVisible() result is picked up.
private boolean hasVisibleConnection(InputSlot slot) {
if (slot == null) {
return true;
}
if (slot.hasSourceNodes()) {
return true;
}
for (FigureConnection c : slot.getConnections()) {
Figure f = c.getOutputSlot().getFigure();
FigureWidget fw = (FigureWidget)scene.findWidget(f);
if (fw.isVisible()) {
return true;
}
}
return false;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, 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,8 +46,8 @@ public abstract class SlotWidget extends Widget implements DoubleClickHandler {
private Slot slot;
private FigureWidget figureWidget;
private static double TEXT_ZOOM_FACTOR = 0.9;
private static double ZOOM_FACTOR = 0.6;
protected static double TEXT_ZOOM_FACTOR = 0.9;
protected static double ZOOM_FACTOR = 0.6;
private DiagramScene diagramScene;
public SlotWidget(Slot slot, DiagramScene scene, Widget parent, FigureWidget fw) {
@@ -58,7 +58,8 @@ public abstract class SlotWidget extends Widget implements DoubleClickHandler {
if (slot.hasSourceNodes()) {
this.setToolTipText("<HTML>" + slot.getToolTipText() + "</HTML>");
}
this.setCheckClipping(true);
// No clipping, to let input slots draw gap markers outside their bounds.
this.setCheckClipping(false);
parent.addChild(this);
Point p = slot.getRelativePosition();