diff --git a/src/hotspot/share/opto/idealGraphPrinter.cpp b/src/hotspot/share/opto/idealGraphPrinter.cpp index 6a28074f4d954..e78178b50d7a9 100644 --- a/src/hotspot/share/opto/idealGraphPrinter.cpp +++ b/src/hotspot/share/opto/idealGraphPrinter.cpp @@ -80,6 +80,10 @@ const char *IdealGraphPrinter::BLOCK_ELEMENT = "block"; const char *IdealGraphPrinter::SUCCESSORS_ELEMENT = "successors"; const char *IdealGraphPrinter::SUCCESSOR_ELEMENT = "successor"; const char *IdealGraphPrinter::ASSEMBLY_ELEMENT = "assembly"; +const char *IdealGraphPrinter::LIVEOUT_ELEMENT = "liveOut"; +const char *IdealGraphPrinter::LIVE_RANGE_ELEMENT = "lrg"; +const char *IdealGraphPrinter::LIVE_RANGE_ID_PROPERTY = "id"; +const char *IdealGraphPrinter::LIVE_RANGES_ELEMENT = "liveRanges"; int IdealGraphPrinter::_file_count = 0; @@ -781,6 +785,12 @@ Node* IdealGraphPrinter::get_load_node(const Node* node) { return load; } +bool IdealGraphPrinter::has_liveness_info() const { + return _chaitin && + _chaitin != (PhaseChaitin *)((intptr_t)0xdeadbeef) && + _chaitin->get_live() != nullptr; +} + void IdealGraphPrinter::walk_nodes(Node* start, bool edges) { VectorSet visited; GrowableArray nodeStack(Thread::current()->resource_area(), 0, 0, nullptr); @@ -877,6 +887,19 @@ void IdealGraphPrinter::print(const char* name, Node* node, GrowableArrayget_live()->live(block); + IndexSetIterator lrgs(liveout); + uint lrg; + while ((lrg = lrgs.next()) != 0) { + begin_elem(LIVE_RANGE_ELEMENT); + print_attr(LIVE_RANGE_ID_PROPERTY, lrg); + end_elem(); + } + tail(LIVEOUT_ELEMENT); + } + tail(BLOCK_ELEMENT); } tail(CONTROL_FLOW_ELEMENT); @@ -900,6 +923,91 @@ void IdealGraphPrinter::print(const char* name, Node* node, GrowableArray_lrg_map.max_lrg_id(); i++) { + begin_head(LIVE_RANGE_ELEMENT); + print_attr(LIVE_RANGE_ID_PROPERTY, i); + end_head(); + head(PROPERTIES_ELEMENT); + const LRG& lrg = _chaitin->lrgs(i); + buffer[0] = 0; + stringStream lrg_mask_stream(buffer, sizeof(buffer) - 1); + lrg.mask().dump(&lrg_mask_stream); + print_prop("mask", buffer); + print_prop("mask_size", lrg.mask_size()); + if (lrg._degree_valid) { + print_prop("degree", lrg.degree()); + } + print_prop("num_regs", lrg.num_regs()); + print_prop("reg_pressure", lrg.reg_pressure()); + print_prop("cost", lrg._cost); + print_prop("area", lrg._area); + print_prop("score", lrg.score()); + if (lrg._risk_bias != 0) { + print_prop("risk_bias", lrg._risk_bias); + } + if (lrg._copy_bias != 0) { + print_prop("copy_bias", lrg._copy_bias); + } + if (lrg.is_singledef()) { + print_prop("is_singledef", TRUE_VALUE); + } + if (lrg.is_multidef()) { + print_prop("is_multidef", TRUE_VALUE); + } + if (lrg._is_oop) { + print_prop("is_oop", TRUE_VALUE); + } + if (lrg._is_float) { + print_prop("is_float", TRUE_VALUE); + } + if (lrg._is_vector) { + print_prop("is_vector", TRUE_VALUE); + } + if (lrg._is_predicate) { + print_prop("is_predicate", TRUE_VALUE); + } + if (lrg._is_scalable) { + print_prop("is_scalable", TRUE_VALUE); + } + if (lrg._was_spilled1) { + print_prop("was_spilled1", TRUE_VALUE); + } + if (lrg._was_spilled2) { + print_prop("was_spilled2", TRUE_VALUE); + } + if (lrg._direct_conflict) { + print_prop("direct_conflict", TRUE_VALUE); + } + if (lrg._fat_proj) { + print_prop("fat_proj", TRUE_VALUE); + } + if (lrg._was_lo) { + print_prop("_was_lo", TRUE_VALUE); + } + if (lrg._has_copy) { + print_prop("has_copy", TRUE_VALUE); + } + if (lrg._at_risk) { + print_prop("at_risk", TRUE_VALUE); + } + if (lrg._must_spill) { + print_prop("must_spill", TRUE_VALUE); + } + if (lrg._is_bound) { + print_prop("is_bound", TRUE_VALUE); + } + if (lrg._msize_valid && lrg._degree_valid && lrg.lo_degree()) { + print_prop("trivial", TRUE_VALUE); + } + tail(PROPERTIES_ELEMENT); + tail(LIVE_RANGE_ELEMENT); + } + tail(LIVE_RANGES_ELEMENT); + } + tail(GRAPH_ELEMENT); _xml->flush(); } diff --git a/src/hotspot/share/opto/idealGraphPrinter.hpp b/src/hotspot/share/opto/idealGraphPrinter.hpp index 042ac694843cc..739f918fab453 100644 --- a/src/hotspot/share/opto/idealGraphPrinter.hpp +++ b/src/hotspot/share/opto/idealGraphPrinter.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, 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 @@ -91,6 +91,10 @@ class IdealGraphPrinter : public CHeapObj { static const char *METHOD_BCI_PROPERTY; static const char *METHOD_SHORT_NAME_PROPERTY; static const char *ASSEMBLY_ELEMENT; + static const char *LIVEOUT_ELEMENT; + static const char *LIVE_RANGE_ELEMENT; + static const char *LIVE_RANGE_ID_PROPERTY; + static const char *LIVE_RANGES_ELEMENT; static int _file_count; networkStream *_network_stream; @@ -114,6 +118,7 @@ class IdealGraphPrinter : public CHeapObj { ciField* get_field(const Node* node); ciField* find_source_field_of_array_access(const Node* node, uint& depth); static Node* get_load_node(const Node* node); + bool has_liveness_info() const; void walk_nodes(Node* start, bool edges); void begin_elem(const char *s); void end_elem(); diff --git a/src/utils/IdealGraphVisualizer/Bytecodes/src/main/java/com/sun/hotspot/igv/bytecodes/SelectBytecodesAction.java b/src/utils/IdealGraphVisualizer/Bytecodes/src/main/java/com/sun/hotspot/igv/bytecodes/SelectBytecodesAction.java index ef9546bbe13f6..d45412cce53ef 100644 --- a/src/utils/IdealGraphVisualizer/Bytecodes/src/main/java/com/sun/hotspot/igv/bytecodes/SelectBytecodesAction.java +++ b/src/utils/IdealGraphVisualizer/Bytecodes/src/main/java/com/sun/hotspot/igv/bytecodes/SelectBytecodesAction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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,7 +41,7 @@ protected void performAction(Node[] activatedNodes) { SelectBytecodesCookie c = activatedNodes[0].getCookie(SelectBytecodesCookie.class); InputGraphProvider p = LookupHistory.getLast(InputGraphProvider.class); if (p != null) { - p.clearSelectedNodes(); + p.clearSelectedElements(); p.addSelectedNodes(c.getNodes(), true); p.centerSelectedNodes(); } diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputBlock.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputBlock.java index 7f3d1a514ef87..6670470b5e8ae 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputBlock.java +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputBlock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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 final String name; private final InputGraph graph; private final Set successors; + private Set liveOut; private boolean artificial; @Override @@ -70,6 +71,15 @@ public boolean equals(Object o) { } } + if (this.liveOut.size() != b.liveOut.size()) { + return false; + } + for (int liveRangeId : this.liveOut) { + if (!b.liveOut.contains(liveRangeId)) { + return false; + } + } + return true; } @@ -78,6 +88,7 @@ public boolean equals(Object o) { this.name = name; nodes = new ArrayList<>(); successors = new LinkedHashSet<>(2); + liveOut = new HashSet(0); artificial = false; } @@ -99,6 +110,14 @@ public void addNode(int id) { nodes.add(node); } + public void addLiveOut(int liveRangeId) { + liveOut.add(liveRangeId); + } + + public Set getLiveOut() { + return Collections.unmodifiableSet(liveOut); + } + public Set getSuccessors() { return Collections.unmodifiableSet(successors); } diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputGraph.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputGraph.java index 3105a817f07ca..987c0e5576e42 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputGraph.java +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputGraph.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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,6 +38,11 @@ public class InputGraph extends Properties.Entity implements FolderElement { private final Map blocks; private final List blockEdges; private final Map nodeToBlock; + private final Map liveRanges; + private Map livenessInfo; + private Map> relatedNodes; + private Map> defNodes; + private Map> useNodes; private final boolean isDiffGraph; private final InputGraph firstGraph; private final InputGraph secondGraph; @@ -58,6 +63,11 @@ private InputGraph(String name, InputGraph firstGraph, InputGraph secondGraph) { nodes = new LinkedHashMap<>(); edges = new ArrayList<>(); blocks = new LinkedHashMap<>(); + liveRanges = new LinkedHashMap<>(); + livenessInfo = new LinkedHashMap<>(); + relatedNodes = new LinkedHashMap<>(); + defNodes = new LinkedHashMap<>(); + useNodes = new LinkedHashMap<>(); blockEdges = new ArrayList<>(); nodeToBlock = new LinkedHashMap<>(); isDiffGraph = firstGraph != null && secondGraph != null; @@ -304,12 +314,66 @@ public Group getGroup() { return parentGroup; } + public void addLiveRange(InputLiveRange lrg) { + liveRanges.put(lrg.getId(), lrg); + relatedNodes.put(lrg.getId(), new HashSet<>()); + defNodes.put(lrg.getId(), new HashSet<>()); + useNodes.put(lrg.getId(), new HashSet<>()); + } + + public InputLiveRange getLiveRange(int liveRangeId) { + return liveRanges.get(liveRangeId); + } + + public Collection getLiveRanges() { + return Collections.unmodifiableCollection(liveRanges.values()); + } + + public void addLivenessInfo(InputNode node, LivenessInfo info) { + livenessInfo.put(node.getId(), info); + if (info.def != null) { + relatedNodes.get(info.def).add(node); + defNodes.get(info.def).add(node); + } + if (info.use != null) { + for (int lrg : info.use) { + relatedNodes.get(lrg).add(node); + useNodes.get(lrg).add(node); + } + } + if (info.join != null) { + for (int lrg : info.join) { + relatedNodes.get(lrg).add(node); + useNodes.get(lrg).add(node); + } + } + } + + public LivenessInfo getLivenessInfoForNode(InputNode node) { + return livenessInfo.get(node.getId()); + } + + public Set getRelatedNodes(int liveRangeId) { + return relatedNodes.get(liveRangeId); + } + + public Set getDefNodes(int liveRangeId) { + return defNodes.get(liveRangeId); + } + + public Set getUseNodes(int liveRangeId) { + return useNodes.get(liveRangeId); + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Graph ").append(getName()).append(" ").append(getProperties().toString()).append("\n"); for (InputNode n : nodes.values()) { sb.append(n.toString()); + if (livenessInfo.containsKey(n.getId())) { + sb.append(" " + livenessInfo.get(n.getId()).toString()); + } sb.append("\n"); } @@ -323,6 +387,11 @@ public String toString() { sb.append("\n"); } + for (InputLiveRange l : liveRanges.values()) { + sb.append(l.toString()); + sb.append("\n"); + } + return sb.toString(); } diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputLiveRange.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputLiveRange.java new file mode 100644 index 0000000000000..5c65d42afd029 --- /dev/null +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputLiveRange.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2025, 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.data; + +import java.util.Objects; + +public class InputLiveRange extends Properties.Entity { + + private int id; + + public InputLiveRange(InputLiveRange n) { + super(n); + setId(n.id); + } + + public InputLiveRange(int id) { + setId(id); + } + + public void setId(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + InputLiveRange other = (InputLiveRange) obj; + return id == other.id && + Objects.equals(getProperties(), other.getProperties()); + } + + @Override + public int hashCode() { + return Objects.hash(id, getProperties()); + } + + @Override + public String toString() { + return "L" + id + " " + getProperties().toString(); + } +} diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/LivenessInfo.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/LivenessInfo.java new file mode 100644 index 0000000000000..4df9838646f9a --- /dev/null +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/LivenessInfo.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025, 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.data; + +import java.util.*; + +public class LivenessInfo { + + public Integer def; + public Set use; + public Set kill; + public Set join; + public Set livein; + public Set liveout; + + public LivenessInfo() {} + + @Override + public String toString() { + return "def: " + def + + ", use: " + use + + ", kill: " + kill + + ", join: " + join + + ", livein: " + livein + + ", liveout: " + liveout; + } + +} diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Parser.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Parser.java index 9db0d83e0ebf7..dfe60372eda3b 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Parser.java +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Parser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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,6 +64,9 @@ public class Parser implements GraphParser { public static final String EDGE_ELEMENT = "edge"; public static final String NODE_ELEMENT = "node"; public static final String NODES_ELEMENT = "nodes"; + public static final String LIVE_RANGE_ELEMENT = "lrg"; + public static final String LIVE_RANGES_ELEMENT = "liveRanges"; + public static final String LIVE_RANGE_ID_PROPERTY = "id"; public static final String VISIBLE_NODES_ELEMENT = "visibleNodes"; public static final String ALL_PROPERTY = "all"; public static final String REMOVE_EDGE_ELEMENT = "removeEdge"; @@ -89,6 +92,7 @@ public class Parser implements GraphParser { public static final String BLOCK_ELEMENT = "block"; public static final String SUCCESSORS_ELEMENT = "successors"; public static final String SUCCESSOR_ELEMENT = "successor"; + public static final String LIVEOUT_ELEMENT = "liveOut"; public static final String DIFFERENCE_PROPERTY = "difference"; private final TopElementHandler xmlData = new TopElementHandler<>(); private final Map differenceEncoding = new HashMap<>(); @@ -150,6 +154,9 @@ protected GraphContext start() { return graphContext; } }; + // + private final HandoverElementHandler liveRangesHandler = new HandoverElementHandler<>(LIVE_RANGES_ELEMENT); + // private final ElementHandler visibleNodesHandler = new ElementHandler<>(VISIBLE_NODES_ELEMENT) { @Override @@ -222,6 +229,41 @@ protected InputBlock start() throws SAXException { return getParentObject(); } }; + // + private final HandoverElementHandler liveOutHandler = new HandoverElementHandler<>(LIVEOUT_ELEMENT); + // + private final ElementHandler liveRangeHandler = new ElementHandler<>(LIVE_RANGE_ELEMENT) { + + @Override + protected InputLiveRange start() throws SAXException { + String s = readRequiredAttribute(NODE_ID_PROPERTY); + int id; + try { + id = lookupID(s); + } catch (NumberFormatException e) { + throw new SAXException(e); + } + InputLiveRange lrg = new InputLiveRange(id); + getParentObject().addLiveRange(lrg); + return lrg; + } + }; + + private final ElementHandler blockLiveRangeHandler = new ElementHandler<>(LIVE_RANGE_ELEMENT) { + + @Override + protected InputBlock start() throws SAXException { + String s = readRequiredAttribute(LIVE_RANGE_ID_PROPERTY); + int liveRangeId; + try { + liveRangeId = Integer.parseInt(s); + } catch (Exception e) { + throw new SAXException(e); + } + getParentObject().addLiveOut(liveRangeId); + return getParentObject(); + } + }; // private final HandoverElementHandler edgesHandler = new HandoverElementHandler<>(EDGES_ELEMENT); // @@ -482,6 +524,7 @@ public Parser(ReadableByteChannel channel, ParseMonitor monitor, GraphDocument c graphHandler.addChild(nodesHandler); graphHandler.addChild(edgesHandler); graphHandler.addChild(controlFlowHandler); + graphHandler.addChild(liveRangesHandler); graphHandler.addChild(graphStatesHandler); controlFlowHandler.addChild(blockHandler); @@ -495,6 +538,10 @@ public Parser(ReadableByteChannel channel, ParseMonitor monitor, GraphDocument c successorsHandler.addChild(successorHandler); blockHandler.addChild(blockNodesHandler); blockNodesHandler.addChild(blockNodeHandler); + blockHandler.addChild(liveOutHandler); + liveOutHandler.addChild(blockLiveRangeHandler); + + liveRangesHandler.addChild(liveRangeHandler); nodesHandler.addChild(nodeHandler); nodesHandler.addChild(removeNodeHandler); @@ -509,6 +556,7 @@ public Parser(ReadableByteChannel channel, ParseMonitor monitor, GraphDocument c nodeHandler.addChild(propertiesHandler); propertiesHandler.addChild(propertyHandler); groupPropertiesHandler.addChild(propertyHandler); + liveRangeHandler.addChild(propertiesHandler); } private int lookupID(String i) { diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Printer.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Printer.java index b098b6ef5da9e..4c82006c0e54a 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Printer.java +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Printer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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 @@ -170,11 +170,29 @@ private static void exportInputGraph(XMLWriter writer, InputGraph graph, InputGr writer.endTag(); // Parser.NODES_ELEMENT } + if (!b.getLiveOut().isEmpty()) { + writer.startTag(Parser.LIVEOUT_ELEMENT); + for (Integer lrg : b.getLiveOut()) { + writer.simpleTag(Parser.LIVE_RANGE_ELEMENT, new Properties(Parser.LIVE_RANGE_ID_PROPERTY, String.valueOf(lrg))); + } + writer.endTag(); // Parser.LIVEOUT_ELEMENT + } + writer.endTag(); // Parser.BLOCK_ELEMENT } writer.endTag(); // Parser.CONTROL_FLOW_ELEMENT + if (!graph.getLiveRanges().isEmpty()) { + writer.startTag(Parser.LIVE_RANGES_ELEMENT); + for (InputLiveRange liveRange : graph.getLiveRanges()) { + writer.startTag(Parser.LIVE_RANGE_ELEMENT, new Properties(Parser.LIVE_RANGE_ID_PROPERTY, String.valueOf(liveRange.getId()))); + writer.writeProperties(liveRange.getProperties()); + writer.endTag(); // Parser.LIVE_RANGE_ELEMENT + } + writer.endTag(); // Parser.LIVE_RANGES_ELEMENT + } + exportStates(writer, graph, contexts); writer.endTag(); // Parser.GRAPH_ELEMENT diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/InputGraphProvider.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/InputGraphProvider.java index b11b29b3d1b55..a13a48b638045 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/InputGraphProvider.java +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/InputGraphProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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 @@ -40,7 +40,7 @@ public interface InputGraphProvider { void addSelectedNodes(Collection nodes, boolean showIfHidden); - void clearSelectedNodes(); + void clearSelectedElements(); /** * @return an iterator walking forward through the {@link InputGraph}s following the {@link #getGraph()} diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/PreProcessor.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/PreProcessor.java new file mode 100644 index 0000000000000..7176a2c06ddb1 --- /dev/null +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/PreProcessor.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.hotspot.igv.data.services; + +import com.sun.hotspot.igv.data.InputGraph; + +public interface PreProcessor { + public void preProcess(InputGraph graph); +} diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/resources/com/sun/hotspot/igv/data/serialization/graphdocument.xsd b/src/utils/IdealGraphVisualizer/Data/src/main/resources/com/sun/hotspot/igv/data/serialization/graphdocument.xsd index 4e02fb64bb911..2d485024f3f26 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/resources/com/sun/hotspot/igv/data/serialization/graphdocument.xsd +++ b/src/utils/IdealGraphVisualizer/Data/src/main/resources/com/sun/hotspot/igv/data/serialization/graphdocument.xsd @@ -143,8 +143,18 @@ + + + + + + + + + + + - diff --git a/src/utils/IdealGraphVisualizer/Difference/src/main/java/com/sun/hotspot/igv/difference/Difference.java b/src/utils/IdealGraphVisualizer/Difference/src/main/java/com/sun/hotspot/igv/difference/Difference.java index 185d219c8deb7..c904e8c6083e8 100644 --- a/src/utils/IdealGraphVisualizer/Difference/src/main/java/com/sun/hotspot/igv/difference/Difference.java +++ b/src/utils/IdealGraphVisualizer/Difference/src/main/java/com/sun/hotspot/igv/difference/Difference.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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 @@ import com.sun.hotspot.igv.data.Properties; import com.sun.hotspot.igv.data.*; +import com.sun.hotspot.igv.data.services.PreProcessor; import com.sun.hotspot.igv.data.services.Scheduler; import java.util.*; import org.openide.util.Lookup; @@ -84,6 +85,8 @@ private static void ensureScheduled(InputGraph a) { s.schedule(a); a.ensureNodesInBlocks(); } + PreProcessor p = Lookup.getDefault().lookup(PreProcessor.class); + p.preProcess(a); } private static InputGraph createDiff(InputGraph a, InputGraph b, Set pairs) { diff --git a/src/utils/IdealGraphVisualizer/Filter/src/main/java/com/sun/hotspot/igv/filter/ColorLiveRangeFilter.java b/src/utils/IdealGraphVisualizer/Filter/src/main/java/com/sun/hotspot/igv/filter/ColorLiveRangeFilter.java new file mode 100644 index 0000000000000..14fb9461c9721 --- /dev/null +++ b/src/utils/IdealGraphVisualizer/Filter/src/main/java/com/sun/hotspot/igv/filter/ColorLiveRangeFilter.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2025, 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.awt.Color; +import java.util.ArrayList; +import java.util.List; + +public class ColorLiveRangeFilter extends AbstractFilter { + + private List colorRules; + private String name; + + public ColorLiveRangeFilter(String name) { + this.name = name; + colorRules = new ArrayList<>(); + } + + @Override + public String getName() { + return name; + } + + @Override + public void apply(Diagram diagram) { + for (ColorRule rule : colorRules) { + if (rule.getSelector() != null) { + List segments = rule.getSelector().selected(diagram); + for (LiveRangeSegment s : segments) { + applyRule(rule, s); + if (rule.getColor() != null) { + s.setColor(rule.getColor()); + } + } + } else { + for (LiveRangeSegment s : diagram.getLiveRangeSegments()) { + applyRule(rule, s); + } + } + } + } + + private void applyRule(ColorRule rule, LiveRangeSegment s) { + if (rule.getColor() != null) { + s.setColor(rule.getColor()); + } + } + + public void addRule(ColorRule r) { + colorRules.add(r); + } + + public static class ColorRule { + + private Color color; + private LiveRangeSelector selector; + + public ColorRule(LiveRangeSelector selector, Color c) { + this.selector = selector; + this.color = c; + } + + public ColorRule(Color c) { + this(null, c); + } + + public Color getColor() { + return color; + } + + public LiveRangeSelector getSelector() { + return selector; + } + } +} diff --git a/src/utils/IdealGraphVisualizer/Filter/src/main/resources/com/sun/hotspot/igv/filter/helper.js b/src/utils/IdealGraphVisualizer/Filter/src/main/resources/com/sun/hotspot/igv/filter/helper.js index b68a027d945e7..a1298cb6ff3f3 100644 --- a/src/utils/IdealGraphVisualizer/Filter/src/main/resources/com/sun/hotspot/igv/filter/helper.js +++ b/src/utils/IdealGraphVisualizer/Filter/src/main/resources/com/sun/hotspot/igv/filter/helper.js @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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,6 +67,11 @@ function matches(property, regexp) { return new MatcherSelector(new Properties.RegexpPropertyMatcher(property, regexp)); } +// Select the nodes for which the given property is defined. +function hasProperty(property) { + return new MatcherSelector(new Properties.InvertPropertyMatcher(new Properties.RegexpPropertyMatcher(property, ""))); +} + // Color the selected nodes. function colorize(selector, color) { var f = new ColorFilter(""); @@ -225,3 +230,15 @@ function removeBlock(selector) { f.addRule(new RemoveBlockFilter.RemoveBlockRule(selector)); f.apply(graph); } + +// Color the selected live ranges. +function colorizeLiveRange(selector, color) { + var f = new ColorLiveRangeFilter(""); + f.addRule(new ColorLiveRangeFilter.ColorRule(selector, color)); + f.apply(graph); +} + +// Select the live ranges whose given property matches a given regular expression. +function matchesLiveRange(property, regexp) { + return new LiveRangeMatcherSelector(new Properties.RegexpPropertyMatcher(property, regexp)); +} diff --git a/src/utils/IdealGraphVisualizer/Graph/src/main/java/com/sun/hotspot/igv/graph/Block.java b/src/utils/IdealGraphVisualizer/Graph/src/main/java/com/sun/hotspot/igv/graph/Block.java index 319f41a924928..c1d04c01c8d6e 100644 --- a/src/utils/IdealGraphVisualizer/Graph/src/main/java/com/sun/hotspot/igv/graph/Block.java +++ b/src/utils/IdealGraphVisualizer/Graph/src/main/java/com/sun/hotspot/igv/graph/Block.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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 @@ -40,6 +40,8 @@ public class Block implements Cluster { protected final InputBlock inputBlock; private Rectangle bounds; private final Diagram diagram; + private List liveRangeIds; + int liveRangeSeparation = -1; public Block(InputBlock inputBlock, Diagram diagram) { this.inputBlock = inputBlock; @@ -70,6 +72,11 @@ public List getVertices() { return vertices; } + public int getLiveRangeSeparation() { + assert liveRangeSeparation > 0; + return liveRangeSeparation; + } + public void setBounds(Rectangle r) { this.bounds = r; } @@ -91,6 +98,19 @@ public Rectangle getBounds() { return bounds; } + public List getLiveRangeIds() { + return liveRangeIds; + } + + public void setLiveRangeIds(List liveRangeIds) { + this.liveRangeIds = liveRangeIds; + int extraDigits = 0; + if (!liveRangeIds.isEmpty()) { + extraDigits = (int)java.lang.Math.log10(Collections.max(liveRangeIds)); + } + liveRangeSeparation = 20 + extraDigits * 7; + } + public int compareTo(Cluster o) { return toString().compareTo(o.toString()); } diff --git a/src/utils/IdealGraphVisualizer/Graph/src/main/java/com/sun/hotspot/igv/graph/Diagram.java b/src/utils/IdealGraphVisualizer/Graph/src/main/java/com/sun/hotspot/igv/graph/Diagram.java index b42dec7eb396e..4fda8f0e575d6 100644 --- a/src/utils/IdealGraphVisualizer/Graph/src/main/java/com/sun/hotspot/igv/graph/Diagram.java +++ b/src/utils/IdealGraphVisualizer/Graph/src/main/java/com/sun/hotspot/igv/graph/Diagram.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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,7 +35,9 @@ public class Diagram { private final Map figures; + private final Hashtable figureHash; private final Map blocks; + private List liveRangeSegments; private final InputGraph inputGraph; private final String nodeText; private final String shortNodeText; @@ -65,7 +67,9 @@ public Diagram(InputGraph graph, String nodeText, String shortNodeText, this.shortNodeText = shortNodeText; this.tinyNodeText = tinyNodeText; this.figures = new LinkedHashMap<>(); + this.figureHash = new Hashtable<>(); this.blocks = new LinkedHashMap<>(8); + this.liveRangeSegments = new ArrayList<>(); this.blockConnections = new HashSet<>(); this.inputGraph = graph; this.cfg = false; @@ -76,7 +80,6 @@ public Diagram(InputGraph graph, String nodeText, String shortNodeText, } Collection nodes = graph.getNodes(); - Hashtable figureHash = new Hashtable<>(); for (InputNode n : nodes) { Figure f = new Figure(this, curId, n); curId++; @@ -128,6 +131,114 @@ public Diagram(InputGraph graph, String nodeText, String shortNodeText, Block s = getBlock(e.getTo()); blockConnections.add(new BlockConnection(p, s, e.getLabel())); } + + Hashtable liveRangeHash = new Hashtable<>(); + for (InputLiveRange lrg : graph.getLiveRanges()) { + liveRangeHash.put(lrg.getId(), lrg); + } + + // Pre-compute live ranges joined by each block. + Map> blockJoined = new HashMap<>(); + for (InputBlock b : graph.getBlocks()) { + blockJoined.put(b, new HashSet<>()); + for (InputNode n : b.getNodes()) { + LivenessInfo l = graph.getLivenessInfoForNode(n); + if (l != null && l.join != null) { + blockJoined.get(b).addAll(l.join); + } + } + } + + for (InputBlock b : graph.getBlocks()) { + if (b.getNodes().isEmpty()) { + continue; + } + Map active = new HashMap<>(); + Set instant = new HashSet<>(); + Set opening = new HashSet<>(); + InputNode header = b.getNodes().get(0); + if (graph.getLivenessInfoForNode(header) == null) { + // No liveness information available, skip. + continue; + } + Set joined = new HashSet<>(); + if (b.getSuccessors().size() == 1) { + // We assume the live-out ranges in this block might only be + // joined if there is exactly one successor block (i.e. the CFG + // does not contain critical edges). + joined.addAll(b.getLiveOut()); + InputBlock succ = b.getSuccessors().iterator().next(); + joined.retainAll(blockJoined.get(succ)); + } + for (int liveRangeId : graph.getLivenessInfoForNode(header).livein) { + active.put(liveRangeId, null); + } + for (InputNode n : b.getNodes()) { + LivenessInfo l = graph.getLivenessInfoForNode(n); + // Commit segments killed by n. + if (l.kill != null) { + for (int liveRangeId : l.kill) { + InputNode startNode = active.get(liveRangeId); + Figure start = startNode == null ? null : figureHash.get(startNode.getId()); + InputNode endNode = n; + Figure end = figureHash.get(endNode.getId()); + LiveRangeSegment s = new LiveRangeSegment(liveRangeHash.get(liveRangeId), getBlock(b), start, end); + if (opening.contains(liveRangeId)) { + s.setOpening(true); + } + s.setClosing(true); + liveRangeSegments.add(s); + active.remove(liveRangeId); + } + } + // Activate new segments. + if (l.def != null && !active.containsKey(l.def)) { + InputNode startNode = n; + if (l.join != null && !l.join.isEmpty()) { + // Start of a "joined" live range. These start always at + // the beginning of the basic block. + startNode = null; + } + active.put(l.def, startNode); + opening.add(l.def); + if (!l.liveout.contains(l.def)) { + instant.add(l.def); + } + } + } + // Commit segments live out the block. + for (Integer liveRangeId : active.keySet()) { + InputNode startNode = active.get(liveRangeId); + Figure start = startNode == null ? null : figureHash.get(startNode.getId()); + LiveRangeSegment s = new LiveRangeSegment(liveRangeHash.get(liveRangeId), getBlock(b), start, null); + if (instant.contains(liveRangeId)) { + s.setInstantaneous(true); + } + if (opening.contains(liveRangeId)) { + s.setOpening(true); + } + if (instant.contains(liveRangeId) || joined.contains(liveRangeId)) { + s.setClosing(true); + } + liveRangeSegments.add(s); + } + } + liveRangeSegments.sort(Comparator.comparingInt(s -> s.getLiveRange().getId())); + for (InputBlock inputBlock : graph.getBlocks()) { + // This loop could be sped up by fusing it with the above one. + List liveRangeSegmentIds = new ArrayList<>(); + int lastAddedLiveRangeId = -1; + for (LiveRangeSegment s : getLiveRangeSegments()) { + if (s.getCluster().getInputBlock().getName().equals(inputBlock.getName())) { + int thisLiveRangeId = s.getLiveRange().getId(); + if (thisLiveRangeId != lastAddedLiveRangeId) { + liveRangeSegmentIds.add(thisLiveRangeId); + lastAddedLiveRangeId = thisLiveRangeId; + } + } + } + blocks.get(inputBlock).setLiveRangeIds(liveRangeSegmentIds); + } } public InputGraph getInputGraph() { @@ -176,6 +287,10 @@ public List
getFigures() { return Collections.unmodifiableList(new ArrayList<>(figures.values())); } + public List getLiveRangeSegments() { + return Collections.unmodifiableList(liveRangeSegments); + } + public FigureConnection createConnection(InputSlot inputSlot, OutputSlot outputSlot, String label) { assert inputSlot.getFigure().getDiagram() == this; assert outputSlot.getFigure().getDiagram() == this; diff --git a/src/utils/IdealGraphVisualizer/Graph/src/main/java/com/sun/hotspot/igv/graph/LiveRangeMatcherSelector.java b/src/utils/IdealGraphVisualizer/Graph/src/main/java/com/sun/hotspot/igv/graph/LiveRangeMatcherSelector.java new file mode 100644 index 0000000000000..5fc456535fa9f --- /dev/null +++ b/src/utils/IdealGraphVisualizer/Graph/src/main/java/com/sun/hotspot/igv/graph/LiveRangeMatcherSelector.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025, 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.data.Properties; +import com.sun.hotspot.igv.data.Properties.PropertyMatcher; +import java.util.List; + +public class LiveRangeMatcherSelector implements LiveRangeSelector { + + private PropertyMatcher matcher; + + public LiveRangeMatcherSelector(PropertyMatcher matcher) { + this.matcher = matcher; + } + + @Override + public List selected(Diagram d) { + Properties.PropertySelector selector = new Properties.PropertySelector<>(d.getLiveRangeSegments()); + List list = selector.selectMultiple(matcher); + return list; + } +} diff --git a/src/utils/IdealGraphVisualizer/Graph/src/main/java/com/sun/hotspot/igv/graph/LiveRangeSegment.java b/src/utils/IdealGraphVisualizer/Graph/src/main/java/com/sun/hotspot/igv/graph/LiveRangeSegment.java new file mode 100644 index 0000000000000..79c58948bbe67 --- /dev/null +++ b/src/utils/IdealGraphVisualizer/Graph/src/main/java/com/sun/hotspot/igv/graph/LiveRangeSegment.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2025, 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.data.InputLiveRange; +import com.sun.hotspot.igv.data.Properties; +import com.sun.hotspot.igv.layout.Segment; +import java.awt.Color; +import java.awt.Point; +import java.util.Set; + +public class LiveRangeSegment extends Properties.Entity implements Segment { + + private InputLiveRange liveRange; + private Block block; + private Figure start; + private Figure end; + private Point startPoint; + private Point endPoint; + private boolean lastOfLiveRange; + private boolean instantaneous; + private boolean opening; + private boolean closing; + private Set segmentSet; + private Color color; + + protected LiveRangeSegment(InputLiveRange liveRange, Block block, Figure start, Figure end) { + this.block = block; + this.liveRange = liveRange; + this.start = start; + this.end = end; + assert(start == null || end == null || (start.getBlock() == end.getBlock())); + lastOfLiveRange = true; + this.color = Color.BLACK; + } + + public InputLiveRange getLiveRange() { + return liveRange; + } + + public Block getCluster() { + return block; + } + + public Figure getStart() { + return start; + } + + public Figure getEnd() { + return end; + } + + public Point getStartPoint() { + return startPoint; + } + + public void setStartPoint(Point startPoint) { + this.startPoint = startPoint; + } + + public Point getEndPoint() { + return endPoint; + } + + public void setEndPoint(Point endPoint) { + this.endPoint = endPoint; + } + + public void setLastOfLiveRange(boolean lastOfLiveRange) { + this.lastOfLiveRange = lastOfLiveRange; + } + + public boolean isLastOfLiveRange() { + return lastOfLiveRange; + } + + public int parentId() { + return this.liveRange.getId(); + } + + public void setInstantaneous(boolean instantaneous) { + this.instantaneous = instantaneous; + } + + public boolean isInstantaneous() { + return instantaneous; + } + + public void setOpening(boolean opening) { + this.opening = opening; + } + + public boolean isOpening() { + return opening; + } + + public void setClosing(boolean closing) { + this.closing = closing; + } + + public boolean isClosing() { + return closing; + } + + public Set getSegmentSet() { + return segmentSet; + } + + public void setSegmentSet(Set segmentSet) { + this.segmentSet = segmentSet; + } + + public void setColor(Color color) { + this.color = color; + } + + public Color getColor() { + return color; + } + + @Override + public String toString() { + return "LiveRangeSegment(" + liveRange + "@B" + block + ", " + start + ", " + end + ")"; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof LiveRangeSegment)) { + return false; + } + LiveRangeSegment other = (LiveRangeSegment)o; + if (getStart() == null && other.getStart() != null) { + return false; + } + if (getStart() != null && other.getStart() == null) { + return false; + } + if (getEnd() == null && other.getEnd() != null) { + return false; + } + if (getEnd() != null && other.getEnd() == null) { + return false; + } + return getLiveRange().equals(((LiveRangeSegment)o).getLiveRange()) + && (getStart() == null || getStart().equals(((LiveRangeSegment)o).getStart())) + && (getEnd() == null || getEnd().equals(((LiveRangeSegment)o).getEnd())); + } + + @Override + public Properties getProperties() { + return liveRange.getProperties(); + } + +} diff --git a/src/utils/IdealGraphVisualizer/Graph/src/main/java/com/sun/hotspot/igv/graph/LiveRangeSelector.java b/src/utils/IdealGraphVisualizer/Graph/src/main/java/com/sun/hotspot/igv/graph/LiveRangeSelector.java new file mode 100644 index 0000000000000..777bc81286e93 --- /dev/null +++ b/src/utils/IdealGraphVisualizer/Graph/src/main/java/com/sun/hotspot/igv/graph/LiveRangeSelector.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025, 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 LiveRangeSelector { + List selected(Diagram d); +} diff --git a/src/utils/IdealGraphVisualizer/HierarchicalLayout/src/main/java/com/sun/hotspot/igv/hierarchicallayout/ClusterNode.java b/src/utils/IdealGraphVisualizer/HierarchicalLayout/src/main/java/com/sun/hotspot/igv/hierarchicallayout/ClusterNode.java index 0de4dfc47ebb5..29ce31c928717 100644 --- a/src/utils/IdealGraphVisualizer/HierarchicalLayout/src/main/java/com/sun/hotspot/igv/hierarchicallayout/ClusterNode.java +++ b/src/utils/IdealGraphVisualizer/HierarchicalLayout/src/main/java/com/sun/hotspot/igv/hierarchicallayout/ClusterNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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 @@ import com.sun.hotspot.igv.layout.Cluster; import com.sun.hotspot.igv.layout.Link; import com.sun.hotspot.igv.layout.Port; +import com.sun.hotspot.igv.layout.Segment; import com.sun.hotspot.igv.layout.Vertex; import java.awt.Dimension; import java.awt.Point; @@ -45,14 +46,19 @@ public class ClusterNode implements Vertex { private Dimension size; private Point position; private final Set subEdges; + private final List subSegments; private boolean root; private final String name; private final int headerVerticalSpace; private final Dimension emptySize; + public static final int EMPTY_BLOCK_LIVE_RANGE_X_OFFSET = 20; + public static final int EMPTY_BLOCK_LIVE_RANGE_Y_OFFSET = 6; + public ClusterNode(Cluster cluster, String name, int headerVerticalSpace, Dimension emptySize) { this.subNodes = new HashSet<>(); this.subEdges = new HashSet<>(); + this.subSegments = new ArrayList<>(); this.cluster = cluster; this.position = new Point(0, 0); this.name = name; @@ -83,6 +89,20 @@ public Set getSubEdges() { return Collections.unmodifiableSet(subEdges); } + public void addSubSegment(Segment s) { + subSegments.add(s); + } + + public void groupSegments() { + for (int i = 1; i < subSegments.size(); i++) { + if (subSegments.get(i).parentId() == subSegments.get(i - 1).parentId()) { + subSegments.get(i - 1).setLastOfLiveRange(false); + } else { + subSegments.get(i - 1).setLastOfLiveRange(true); + } + } + } + public void updateSize() { calculateSize(); @@ -106,7 +126,7 @@ public String toString() { private void calculateSize() { - if (subNodes.isEmpty()) { + if (subNodes.isEmpty() && subSegments.isEmpty()) { size = emptySize; return; } @@ -137,6 +157,18 @@ private void calculateSize() { } } + for (Segment segment : subSegments) { + Point s = segment.getStartPoint(); + minX = Math.min(minX, s.x); + maxX = Math.max(maxX, s.x + cluster.getLiveRangeSeparation()); + } + if (!subSegments.isEmpty()) { + maxX += cluster.getLiveRangeSeparation(); + } + if (subNodes.isEmpty()) { + maxX += ClusterNode.EMPTY_BLOCK_LIVE_RANGE_X_OFFSET; + } + size = new Dimension(maxX - minX, maxY - minY + headerVerticalSpace); // Normalize coordinates @@ -173,12 +205,16 @@ public Point getPosition() { } public void setPosition(Point pos) { + int startX = pos.x + PADDING; + int startY = pos.y + PADDING; + int minY = Integer.MAX_VALUE; this.position = pos; for (Vertex n : subNodes) { Point cur = new Point(n.getPosition()); - cur.translate(pos.x + PADDING, pos.y + PADDING); + cur.translate(startX, startY); n.setPosition(cur); + minY = Math.min(minY, cur.y); } for (Link e : subEdges) { @@ -187,7 +223,7 @@ public void setPosition(Point pos) { for (Point p : arr) { if (p != null) { Point p2 = new Point(p); - p2.translate(pos.x + PADDING, pos.y + PADDING); + p2.translate(startX, startY); newArr.add(p2); } else { newArr.add(null); @@ -196,6 +232,14 @@ public void setPosition(Point pos) { e.setControlPoints(newArr); } + + if (subNodes.isEmpty()) { + minY = startY + 12; + } + for (Segment s : subSegments) { + s.getStartPoint().translate(startX + cluster.getLiveRangeSeparation(), minY); + s.getEndPoint().translate(startX + cluster.getLiveRangeSeparation(), minY); + } } public Cluster getCluster() { @@ -227,6 +271,10 @@ public Set getSubNodes() { return subNodes; } + public List getSubSegments() { + return subSegments; + } + @Override public boolean equals(Object obj) { if (this == obj) return true; diff --git a/src/utils/IdealGraphVisualizer/HierarchicalLayout/src/main/java/com/sun/hotspot/igv/hierarchicallayout/HierarchicalCFGLayoutManager.java b/src/utils/IdealGraphVisualizer/HierarchicalLayout/src/main/java/com/sun/hotspot/igv/hierarchicallayout/HierarchicalCFGLayoutManager.java index 74a7b07441494..0b6c71064bdff 100644 --- a/src/utils/IdealGraphVisualizer/HierarchicalLayout/src/main/java/com/sun/hotspot/igv/hierarchicallayout/HierarchicalCFGLayoutManager.java +++ b/src/utils/IdealGraphVisualizer/HierarchicalLayout/src/main/java/com/sun/hotspot/igv/hierarchicallayout/HierarchicalCFGLayoutManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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,13 @@ import com.sun.hotspot.igv.layout.Cluster; import com.sun.hotspot.igv.layout.Link; +import com.sun.hotspot.igv.layout.Segment; import com.sun.hotspot.igv.layout.Vertex; -import java.awt.*; +import java.awt.Canvas; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Point; import java.util.*; public class HierarchicalCFGLayoutManager extends LayoutManager { @@ -37,10 +42,12 @@ public class HierarchicalCFGLayoutManager extends LayoutManager { private final Set clusterLinks; Map clusterNodesMap; Map clusterEdgesMap; + private List segments; public HierarchicalCFGLayoutManager(Set clusterLinks, Set clusters) { this.clusterLinks = clusterLinks; this.clusters = clusters; + this.segments = new ArrayList<>(); // Anticipate block label sizes to dimension blocks appropriately. Canvas canvas = new Canvas(); Font font = new Font("Arial", Font.BOLD, 14); @@ -54,19 +61,64 @@ public void setCutEdges(boolean enable) { manager.setCutEdges(enable); } - private static void doLinearLayout(ClusterNode clusterNode) { + private void doLinearLayout(ClusterNode clusterNode) { Cluster cluster = clusterNode.getCluster(); + clusterNode.groupSegments(); LayoutGraph graph = new LayoutGraph(clusterNode.getSubEdges(), clusterNode.getSubNodes()); - int curY = 0; + + // Compute list of vertices that are actually laid out. + List vertices = new ArrayList<>(cluster.getVertices().size()); for (Vertex vertex : cluster.getVertices()) { - if (graph.containsVertex(vertex)) { - vertex.setPosition(new Point(0, curY)); - curY += vertex.getSize().height; + if (graph.containsVertex(vertex)) { // The vertex is visible. + vertices.add(vertex); + } + } + int curY = 0; + for (Vertex vertex : vertices) { + vertex.setPosition(new Point(0, curY)); + curY += vertex.getSize().height; + } + + // If live segments are available, compute their position. + if (vertices.isEmpty()) { + int x = ClusterNode.EMPTY_BLOCK_LIVE_RANGE_X_OFFSET; + final int y = ClusterNode.EMPTY_BLOCK_LIVE_RANGE_Y_OFFSET; + for (Segment s : clusterNode.getSubSegments()) { + s.setStartPoint(new Point(x, y)); + s.setEndPoint(new Point(x, y)); + if (s.isLastOfLiveRange()) { + x += s.getCluster().getLiveRangeSeparation(); + } + } + } else { + Vertex first = vertices.get(0); + int x = (int)first.getSize().getWidth(); + int entryY = (int)first.getPosition().getY(); + Vertex last = vertices.get(vertices.size() - 1); + int exitY = (int)last.getPosition().getY() + (int)last.getSize().getHeight(); + for (Segment s : clusterNode.getSubSegments()) { + Vertex start = s.getStart(); + Vertex end = s.getEnd(); + int startY = s.getStart() == null ? entryY : (start.getPosition().y + (int)(start.getSize().getHeight() / 2)); + s.setStartPoint(new Point(x, startY)); + int endY = end == null ? exitY : (end.getPosition().y + (int)(end.getSize().getHeight() / 2)); + if (s.isInstantaneous()) { + endY = startY; + } + s.setEndPoint(new Point(x, endY)); + if (s.isLastOfLiveRange()) { + x += s.getCluster().getLiveRangeSeparation(); + } } } + clusterNode.updateSize(); } + public void setSegments(List segments) { + this.segments = segments; + } + public void doLayout(LayoutGraph graph) { // Create cluster-level nodes and edges. clusterNodesMap = createClusterNodes(graph.getVertices()); @@ -74,6 +126,13 @@ public void doLayout(LayoutGraph graph) { clusterEdgesMap = createClusterEdges(clusterNodesMap); assert clusterEdgesMap.size() == clusterLinks.size(); + // Compute sub-segments in every cluster. + for (Segment s : segments) { + Cluster c = s.getCluster(); + assert c != null : "Cluster of segment " + s + " is null!"; + clusterNodesMap.get(c).addSubSegment(s); + } + // Compute layout for each cluster. for (ClusterNode clusterNode : clusterNodesMap.values()) { doLinearLayout(clusterNode); diff --git a/src/utils/IdealGraphVisualizer/Layout/src/main/java/com/sun/hotspot/igv/layout/Cluster.java b/src/utils/IdealGraphVisualizer/Layout/src/main/java/com/sun/hotspot/igv/layout/Cluster.java index 84ddd5dd69522..5dee43f9224c2 100644 --- a/src/utils/IdealGraphVisualizer/Layout/src/main/java/com/sun/hotspot/igv/layout/Cluster.java +++ b/src/utils/IdealGraphVisualizer/Layout/src/main/java/com/sun/hotspot/igv/layout/Cluster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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 @@ -45,4 +45,6 @@ public interface Cluster extends Comparable { List getVertices(); Set getSuccessors(); + + int getLiveRangeSeparation(); } diff --git a/src/utils/IdealGraphVisualizer/Layout/src/main/java/com/sun/hotspot/igv/layout/Segment.java b/src/utils/IdealGraphVisualizer/Layout/src/main/java/com/sun/hotspot/igv/layout/Segment.java new file mode 100644 index 0000000000000..6591fcb4a1dae --- /dev/null +++ b/src/utils/IdealGraphVisualizer/Layout/src/main/java/com/sun/hotspot/igv/layout/Segment.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025, 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.layout; + +import java.awt.Point; + +public interface Segment { + Cluster getCluster(); + Vertex getStart(); + Vertex getEnd(); + Point getStartPoint(); + void setStartPoint(Point startPoint); + Point getEndPoint(); + void setEndPoint(Point endPoint); + boolean isLastOfLiveRange(); + void setLastOfLiveRange(boolean lastOfLiveRange); + int parentId(); + boolean isInstantaneous(); +} diff --git a/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/java/com/sun/hotspot/igv/servercompiler/ServerCompilerPreProcessor.java b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/java/com/sun/hotspot/igv/servercompiler/ServerCompilerPreProcessor.java new file mode 100644 index 0000000000000..58cc5c242a4bc --- /dev/null +++ b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/java/com/sun/hotspot/igv/servercompiler/ServerCompilerPreProcessor.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.hotspot.igv.servercompiler; + +import com.sun.hotspot.igv.data.*; +import com.sun.hotspot.igv.data.services.PreProcessor; +import org.openide.util.lookup.ServiceProvider; +import java.util.*; +import java.util.stream.*; + +@ServiceProvider(service = PreProcessor.class) +public class ServerCompilerPreProcessor implements PreProcessor { + + private static boolean isPhi(InputNode node, int defLiveRange, List uses) { + String nodeName = node.getProperties().get("name"); + if (nodeName == null) { + return false; + } + if (!nodeName.equals("Phi")) { + return false; + } + Set useSet = new HashSet<>(uses); + if (useSet.size() == 1 && useSet.iterator().next() == defLiveRange) { + // The phi operands have been coalesced, treat as a regular instruction. + return false; + } + return true; + } + + private static int getNumericPropertyOrZero(InputNode node, String k) { + int v = 0; + try { + v = Integer.parseInt(node.getProperties().get(k)); + } catch (Exception e) { + } + return v; + } + + private static boolean isAllocatableLiveRange(int liveRangeId) { + return liveRangeId > 0; + } + + private String liveRangeList(Stream s) { + return s.sorted().map(String::valueOf).collect(Collectors.joining(", ")); + } + + @Override + public void preProcess(InputGraph graph) { + if (graph.getLiveRanges().isEmpty()) { + // No block-level liveness information available, move on. + return; + } + // Build a map from nodes to live ranges used. + Map> usedLiveRanges = new HashMap<>(graph.getNodes().size()); + for (InputEdge e : graph.getEdges()) { + int liveRangeId = getNumericPropertyOrZero(graph.getNode(e.getFrom()), "lrg"); + if (isAllocatableLiveRange(liveRangeId)) { + int toId = e.getTo(); + if (usedLiveRanges.get(toId) == null) { + usedLiveRanges.put(toId, new ArrayList()); + } + usedLiveRanges.get(toId).add(liveRangeId); + } + } + // Propagate block-level live-out information to each node. + for (InputBlock b : graph.getBlocks()) { + Set liveOut = new HashSet<>(); + for (int lrg : b.getLiveOut()) { + liveOut.add(lrg); + } + for (int i = b.getNodes().size() - 1; i >= 0; i--) { + LivenessInfo livenessInfo = new LivenessInfo(); + InputNode n = b.getNodes().get(i); + String liveOutList = liveRangeList(liveOut.stream()); + n.getProperties().setProperty("liveout", liveOutList); + livenessInfo.liveout = new HashSet<>(liveOut); + int defLiveRange = getNumericPropertyOrZero(n, "lrg"); + if (isAllocatableLiveRange(defLiveRange)) { + livenessInfo.def = defLiveRange; + // Otherwise it is missing or a non-allocatable live range. + liveOut.remove(defLiveRange); + } + List uses = usedLiveRanges.get(n.getId()); + if (uses != null) { + String useList = liveRangeList(uses.stream()); + if (isPhi(n, defLiveRange, uses)) { + // A phi's uses are not live simultaneously. + // Conceptually, they die at the block's incoming egdes. + n.getProperties().setProperty("joins", useList); + livenessInfo.join = new HashSet<>(uses); + } else { + n.getProperties().setProperty("uses", useList); + livenessInfo.use = new HashSet<>(uses); + // Compute kill set: all uses that are not in the + // live-out set of the node. + Set kills = new HashSet<>(); + for (int useLiveRange : uses) { + if (!liveOut.contains(useLiveRange) && useLiveRange != defLiveRange) { + kills.add(useLiveRange); + } + } + if (!kills.isEmpty()) { + String killList = liveRangeList(kills.stream()); + n.getProperties().setProperty("kills", killList); + livenessInfo.kill = new HashSet<>(kills); + } + for (int useLiveRange : uses) { + liveOut.add(useLiveRange); + } + } + } + String liveInList = liveRangeList(liveOut.stream()); + n.getProperties().setProperty("livein", liveInList); + livenessInfo.livein = new HashSet<>(liveOut); + graph.addLivenessInfo(n, livenessInfo); + } + } + } +} diff --git a/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/colorLiveRanges.filter b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/colorLiveRanges.filter new file mode 100644 index 0000000000000..4e5883ab7555d --- /dev/null +++ b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/colorLiveRanges.filter @@ -0,0 +1,3 @@ +// Fade out live ranges allocated to stack lots. + +colorizeLiveRange(matchesLiveRange("mask", "\\[rS.+\\]"), Color.LIGHT_GRAY); diff --git a/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/showLiveness.filter b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/showLiveness.filter new file mode 100644 index 0000000000000..09d12d6c84710 --- /dev/null +++ b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/showLiveness.filter @@ -0,0 +1,41 @@ +// This filter replaces the extra-label line with liveness information such as +// uses, defs, and live-out sets, if available. + +function formatLiveRange(lrg) { + flrg = "L"; + flrg += lrg.trim(); + return flrg; +} + +function liveRangeSet(integerList) { + return "{" + (integerList.split(",").map(function(lrg) {return formatLiveRange(lrg);})).join(", ") + "}"; +} + +// Replace extra label with liveness info. +function addLivenessInfo(lrg, idx, liveout, uses, joins, kills) { + if (lrg == null || liveout == null) { + return ""; + } + elements = []; + if (Number(lrg) > 0) { + elements.push("def: " + formatLiveRange(lrg)); + } + if (uses != null) { + elements.push("use: " + liveRangeSet(uses)); + } + if (joins != null) { + elements.push("join: " + liveRangeSet(joins)); + } + if (kills != null) { + elements.push("kill: " + liveRangeSet(kills)); + } + if (liveout.length > 0) { + elements.push("liveout: " + liveRangeSet(liveout)); + } + return elements.join(", "); +} + +editProperty(or([hasProperty("liveout"), hasProperty("uses"), hasProperty("joins"), hasProperty("kills")]), + ["lrg", "idx", "liveout", "uses", "joins", "kills"], + "extra_label", + function(propertyValues) {return addLivenessInfo(propertyValues[0], propertyValues[1], propertyValues[2], propertyValues[3], propertyValues[4], propertyValues[5]);}); diff --git a/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/showRegisterAllocationOnly.filter b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/showRegisterAllocationOnly.filter new file mode 100644 index 0000000000000..d4625d864392a --- /dev/null +++ b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/showRegisterAllocationOnly.filter @@ -0,0 +1,5 @@ +// Remove all nodes except those that affect register allocation. +remove(and([matches("lrg", "0"), + not(hasProperty("uses")), + not(hasProperty("joins")), + not(hasProperty("kills"))])); diff --git a/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/layer.xml b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/layer.xml index 808a281fee4e1..db4682f1cab86 100644 --- a/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/layer.xml +++ b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/layer.xml @@ -85,5 +85,17 @@ + + + + + + + + + + + + diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/BlockQuickSearch.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/BlockQuickSearch.java index 79727ad902851..715b95598656c 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/BlockQuickSearch.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/BlockQuickSearch.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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,124 +25,30 @@ import com.sun.hotspot.igv.data.InputBlock; import com.sun.hotspot.igv.data.InputGraph; -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.ArrayList; -import java.util.List; -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; +import java.util.*; -public class BlockQuickSearch implements SearchProvider { +public class BlockQuickSearch extends SimpleQuickSearch { @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 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 editor = EditorTopComponent.getActive(); - assert(editor != null); - if (theGraph != null) { - editor.getModel().selectGraph(theGraph); - } - editor.clearSelectedNodes(); - editor.addSelectedNodes(b.getNodes(), true); - editor.centerSelectedNodes(); - editor.requestActive(); - }, - "B" + b.getName() + (theGraph != null ? " in " + theGraph.getName() : ""))) { - return; - } - } - } + String prefix() { + return "B"; } - private List findMatches(String blockName, InputGraph inputGraph, SearchResponse response) { - try { - RegexpPropertyMatcher matcher = new RegexpPropertyMatcher("", blockName, Pattern.CASE_INSENSITIVE); - List 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; + @Override + String id(Object entity) { + assert entity instanceof InputBlock; + return ((InputBlock)entity).getName(); } - 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); + @Override + Collection getAllEntities(InputGraph inputGraph) { + return new ArrayList<>(inputGraph.getBlocks()); } + @Override + void selectEntity(EditorTopComponent editor, Object entity) { + assert entity instanceof InputBlock; + editor.addSelectedNodes(((InputBlock)entity).getNodes(), true); + editor.centerSelectedNodes(); + } } diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramScene.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramScene.java index 99ae3380bb39d..2e46970aed55a 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramScene.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramScene.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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 @@ -59,6 +59,7 @@ import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; import org.openide.nodes.Sheet; +import org.openide.util.ImageUtilities; import org.openide.util.Lookup; import org.openide.util.lookup.AbstractLookup; import org.openide.util.lookup.InstanceContent; @@ -81,6 +82,7 @@ public class DiagramScene extends ObjectScene implements DiagramViewer, DoubleCl private final LayerWidget mainLayer; private final LayerWidget blockLayer; private final LayerWidget connectionLayer; + private final LayerWidget segmentLayer; private final Widget shadowWidget; private final Widget pointerWidget; private final DiagramViewModel model; @@ -224,6 +226,7 @@ public void filteredChanged(SelectionCoordinator coordinator) { } setFigureSelection(selectedFigures); centerSelectedFigures(); + centerSelectedLiveRanges(); validateAll(); } } @@ -342,6 +345,10 @@ public void select(Widget widget, Point localLocation, boolean invertSelection) connectionLayer.setBorder(emptyBorder); addChild(connectionLayer); + segmentLayer = new LayerWidget(this); + segmentLayer.setBorder(emptyBorder); + addChild(segmentLayer); + mainLayer = new LayerWidget(this); mainLayer.setBorder(emptyBorder); addChild(mainLayer); @@ -374,7 +381,7 @@ public void select(Widget widget, Point localLocation, boolean invertSelection) rectangle.height *= -1; } - clearSelectedNodes(); + clearSelectedElements(); Set selectedObjects = new HashSet<>(); for (Figure f : getModel().getDiagram().getFigures()) { FigureWidget w = getWidget(f); @@ -429,10 +436,28 @@ public void selectionChanged(ObjectSceneEvent e, Set oldSet, Set return; } - content.set(newSet, null); + // Remove duplicate live range segments (i.e. segments that + // represent the same live range in different basic blocks). + Set newUnique = new HashSet<>(); + Set visitedLiveRanges = new HashSet<>(); + for (Object o : newSet) { + if (o instanceof Properties.Provider && + o instanceof LiveRangeSegment) { + int liveRangeId = ((LiveRangeSegment) o).getLiveRange().getId(); + if (!visitedLiveRanges.contains(liveRangeId)) { + newUnique.add(o); + visitedLiveRanges.add(liveRangeId); + } + } else { + newUnique.add(o); + } + } + + content.set(newUnique, null); Set nodeSelection = new HashSet<>(); - for (Object o : newSet) { + Set liveRangeSelection = new HashSet<>(); + for (Object o : newUnique) { if (o instanceof Properties.Provider) { final Properties.Provider provider = (Properties.Provider) o; AbstractNode node = new AbstractNode(Children.LEAF) { @@ -444,7 +469,14 @@ protected Sheet createSheet() { return s; } }; - node.setDisplayName(provider.getProperties().get("name")); + String displayName = null; + if (o instanceof Figure || o instanceof Slot) { + displayName = provider.getProperties().get("idx") + " " + + provider.getProperties().get("name"); + } else if (o instanceof LiveRangeSegment) { + displayName = "L" + ((LiveRangeSegment) o).getLiveRange().getId(); + } + node.setDisplayName(displayName); content.add(node); } @@ -453,9 +485,12 @@ protected Sheet createSheet() { nodeSelection.add(((Figure) o).getInputNode().getId()); } else if (o instanceof Slot) { nodeSelection.addAll(((Slot) o).getSource().getSourceNodesAsSet()); + } else if (o instanceof LiveRangeSegment) { + liveRangeSelection.add(((LiveRangeSegment) o).getLiveRange().getId()); } } getModel().setSelectedNodes(nodeSelection); + getModel().setSelectedLiveRanges(liveRangeSelection); boolean b = selectedCoordinatorListener.isEnabled(); selectedCoordinatorListener.setEnabled(false); @@ -573,6 +608,53 @@ public void actionPerformed(ActionEvent e) { return action; } + public Action createGotoNodesAction(String name, Set
figures) { + String iconResource = "com/sun/hotspot/igv/view/images/selectNodes.png"; + Action action = new AbstractAction(name, new ImageIcon(ImageUtilities.loadImage(iconResource))) { + @Override + public void actionPerformed(ActionEvent e) { + setFigureSelection(figures); + model.showFigures(model.getSelectedFigures()); + centerSelectedFigures(); + } + }; + + action.setEnabled(true); + return action; + } + + private Action createGotoLiveRangeAction(String name, String iconResource, Set liveRanges) { + Action action = new AbstractAction(name, new ImageIcon(ImageUtilities.loadImage(iconResource))) { + @Override + public void actionPerformed(ActionEvent e) { + Set segments = liveRangeSegmentSet(liveRanges); + setLiveRangeSegmentSelection(segments); + Diagram diagram = getModel().getDiagram(); + Set
figures = new HashSet<>(); + for (InputLiveRange liveRange : liveRanges) { + for (InputNode node : diagram.getInputGraph().getRelatedNodes(liveRange.getId())) { + figures.add((diagram.getFigure(node))); + } + } + model.showFigures(figures); + centerSelectedLiveRanges(); + } + }; + + action.setEnabled(true); + return action; + } + + public Action createGotoLiveRangeAction(String name, Set liveRanges) { + return createGotoLiveRangeAction(name, "com/sun/hotspot/igv/view/images/selectLiveRanges.png", liveRanges); + } + + public Action createGotoLiveRangeAction(InputLiveRange liveRange) { + return createGotoLiveRangeAction("L" + liveRange.getId(), + "com/sun/hotspot/igv/view/images/liveRange.png", + Collections.singleton(liveRange)); + } + private void clearObjects() { Set objectSet = new HashSet<>(getObjects()); for (Object object : objectSet) { @@ -829,6 +911,7 @@ private void update() { updateFigureWidths(); rebuildMainLayer(); rebuildBlockLayer(); + rebuildSegmentLayer(); relayout(); rebuilding = false; } @@ -841,15 +924,18 @@ private void hiddenNodesChanged() { private void relayout() { rebuilding = true; Set oldVisibleFigureWidgets = getVisibleFigureWidgets(); + Set oldVisibleLiveRangeWidgets = getVisibleLiveRangeWidgets(); Set oldVisibleBlockWidgets = getVisibleBlockWidgets(); updateVisibleFigureWidgets(); updateNodeHull(); + updateVisibleLiveRangeWidgets(); updateVisibleBlockWidgets(); validateAll(); Set
visibleFigures = getVisibleFigures(); Set visibleConnections = getVisibleConnections(); + List visibleLiveRangeSegments = getVisibleLiveRangeSegments(); if (getModel().getShowFreeInteractive()) { doFreeInteractiveLayout(visibleFigures, visibleConnections); } else if (getModel().getShowStableSea()) { @@ -859,15 +945,22 @@ private void relayout() { } else if (getModel().getShowBlocks()) { doClusteredLayout(visibleFigures, visibleConnections); } else if (getModel().getShowCFG()) { - doCFGLayout(visibleFigures, visibleConnections); + doCFGLayout(visibleFigures, visibleConnections, visibleLiveRangeSegments); } rebuildConnectionLayer(); + if (getModel().getShowCFG() && getModel().getShowLiveRanges()) { + updateLiveRangeIdsInBlockWidgets(); + repaintLiveRangeWidgets(); + } updateFigureWidgetLocations(oldVisibleFigureWidgets); + updateLiveRangeWidgetLocations(oldVisibleLiveRangeWidgets); updateBlockWidgetBounds(oldVisibleBlockWidgets); validateAll(); - setFigureSelection(model.getSelectedFigures()); + setElementSelection(model.getSelectedFigures(), + model.getSelectedLiveRangeSegments()); centerSelectedFigures(); + centerSelectedLiveRanges(); rebuilding = false; } @@ -922,6 +1015,36 @@ private boolean isVisibleFigureConnection(FigureConnection figureConnection) { return w1.isVisible() && w2.isVisible(); } + private boolean isVisibleBlock(Block b) { + BlockWidget bw = getWidget(b); + return bw != null && getWidget(b, BlockWidget.class).isVisible(); + } + + private boolean isVisibleLiveRange(int liveRangeId) { + if (!getModel().getShowLiveRanges()) { + return false; + } + Set relatedNodes = getModel().getGraph().getRelatedNodes(liveRangeId); + for (InputNode n : relatedNodes) { + if (!getModel().getDiagram().hasFigure(n)) { + return false; + } + Figure f = getModel().getDiagram().getFigure(n); + FigureWidget fw = getWidget(f); + if (isVisibleBlock(f.getBlock()) && + (fw == null || !fw.isVisible())) { + return false; + } + } + return true; + } + + private boolean isVisibleLiveRangeSegment(LiveRangeSegment s) { + return isVisibleLiveRange(s.getLiveRange().getId()) && + isVisibleBlock(s.getCluster()); + } + + private void doFreeInteractiveLayout(Set
visibleFigures, Set visibleConnections) { layoutMover = freeInteractiveLayoutManager; freeInteractiveLayoutManager.setCutEdges(model.getCutEdges()); @@ -954,10 +1077,11 @@ private void doClusteredLayout(Set
visibleFigures, Set visib clusterLayoutManager.doLayout(new LayoutGraph(visibleConnections, visibleFigures)); } - private void doCFGLayout(Set
visibleFigures, Set visibleConnections) { + private void doCFGLayout(Set
visibleFigures, Set visibleConnections, List segments) { layoutMover = null; HierarchicalCFGLayoutManager cfgLayoutManager = new HierarchicalCFGLayoutManager(getVisibleBlockConnections(), getVisibleBlocks()); cfgLayoutManager.setCutEdges(model.getCutEdges()); + cfgLayoutManager.setSegments(new ArrayList<>(segments)); cfgLayoutManager.doLayout(new LayoutGraph(visibleConnections, visibleFigures)); } @@ -1210,7 +1334,7 @@ public void setInteractionMode(InteractionMode mode) { @Override public void handleDoubleClick(Widget w, WidgetAction.WidgetMouseEvent e) { - clearSelectedNodes(); + clearSelectedElements(); } private class ConnectionSet { @@ -1234,8 +1358,21 @@ private void gotoBlock(final Block block) { } } - @Override - public void addSelectedNodes(Collection nodes, boolean showIfHidden) { + public Set liveRangeSegmentSet(Collection liveRanges) { + Set liveRangeIds = new HashSet<>(); + for (InputLiveRange liveRange : liveRanges) { + liveRangeIds.add(liveRange.getId()); + } + Set segments = new HashSet<>(); + for (LiveRangeSegment segment : model.getDiagram().getLiveRangeSegments()) { + if (liveRangeIds.contains(segment.getLiveRange().getId())) { + segments.add(segment); + } + } + return segments; + } + + private Set
figureSet(Collection nodes) { Set nodeIds = new HashSet<>(model.getSelectedNodes()); for (InputNode inputNode : nodes) { nodeIds.add(inputNode.getId()); @@ -1246,14 +1383,34 @@ public void addSelectedNodes(Collection nodes, boolean showIfHidden) selectedFigures.add(figure); } } - setFigureSelection(selectedFigures); + return selectedFigures; + } + + @Override + public void addSelectedNodes(Collection nodes, boolean showIfHidden) { + setFigureSelection(figureSet(nodes)); if (showIfHidden) { model.showFigures(model.getSelectedFigures()); } } @Override - public void clearSelectedNodes() { + public void addSelectedLiveRanges(Collection liveRanges, boolean showIfHidden) { + setLiveRangeSegmentSelection(liveRangeSegmentSet(liveRanges)); + } + + @Override + public void addSelectedElements(Collection nodes, + Collection liveRanges, + boolean showIfHidden) { + setElementSelection(figureSet(nodes), liveRangeSegmentSet(liveRanges)); + if (showIfHidden) { + model.showFigures(model.getSelectedFigures()); + } + } + + @Override + public void clearSelectedElements() { setSelectedObjects(Collections.emptySet()); } @@ -1281,6 +1438,30 @@ public void centerSelectedFigures() { } } + @Override + public void centerSelectedLiveRanges() { + Set selectedLiveRanges = model.getSelectedLiveRangeSegments(); + Rectangle overallRect = null; + for (LiveRangeSegment segment : selectedLiveRanges) { + LiveRangeWidget liveRangeWidget = getWidget(segment); + if (liveRangeWidget != null) { + Rectangle bounds = liveRangeWidget.getBounds(); + if (bounds != null) { + Point location = liveRangeWidget.getLocation(); + Rectangle rect = new Rectangle(location.x, location.y, bounds.width, bounds.height); + if (overallRect == null) { + overallRect = rect; + } else { + overallRect = overallRect.union(rect); + } + } + } + } + if (overallRect != null) { + centerRectangle(overallRect); + } + } + private void centerRectangle(Rectangle r) { Rectangle rect = convertSceneToView(r); Rectangle viewRect = scrollPane.getViewport().getViewRect(); @@ -1311,6 +1492,16 @@ private void setFigureSelection(Set
list) { super.setSelectedObjects(new HashSet<>(list)); } + private void setLiveRangeSegmentSelection(Set list) { + super.setSelectedObjects(new HashSet<>(list)); + } + + private void setElementSelection(Set
figures, Set segments) { + Set elements = new HashSet<>(figures); + elements.addAll(segments); + super.setSelectedObjects(elements); + } + @Override public void resetUndoRedoManager() { undoRedoManager = new UndoRedo.Manager(); @@ -1371,7 +1562,33 @@ private void rebuildConnectionLayer() { newWidgets.clear(); } - private Set getVisibleFigureWidgets() { + private void rebuildSegmentLayer() { + segmentLayer.removeChildren(); + if (getModel().getShowCFG() && getModel().getShowLiveRanges()) { + Map> segments = new HashMap<>(); + for (LiveRangeSegment segment : getModel().getDiagram().getLiveRangeSegments()) { + int liveRangeId = segment.getLiveRange().getId(); + if (!segments.containsKey(liveRangeId)) { + segments.put(liveRangeId, new HashSet<>()); + } + segments.get(liveRangeId).add(segment); + } + for (Set segmentSet : segments.values()) { + for (LiveRangeSegment segment : segmentSet) { + segment.setStartPoint(null); + segment.setEndPoint(null); + segment.setSegmentSet(segmentSet); + LiveRangeWidget segmentWidget = new LiveRangeWidget(segment, this, 0); + segmentWidget.setVisible(false); + addObject(segment, segmentWidget); + segmentWidget.getActions().addAction(hoverAction); + segmentLayer.addChild(segmentWidget); + } + } + } + } + + private Set getVisibleFigureWidgets() { Set visibleFigureWidgets = new HashSet<>(); for (Figure figure : getModel().getDiagram().getFigures()) { FigureWidget figureWidget = getWidget(figure); @@ -1382,6 +1599,17 @@ private Set getVisibleFigureWidgets() { return visibleFigureWidgets; } + private Set getVisibleLiveRangeWidgets() { + Set visibleLiveRangeWidgets = new HashSet<>(); + for (LiveRangeSegment segment : getModel().getDiagram().getLiveRangeSegments()) { + LiveRangeWidget liveRangeWidget = getWidget(segment); + if (liveRangeWidget != null && liveRangeWidget.isVisible()) { + visibleLiveRangeWidgets.add(liveRangeWidget); + } + } + return visibleLiveRangeWidgets; + } + private Set getVisibleBlockWidgets() { Set visibleBlockWidgets = new HashSet<>(); if (getModel().getShowBlocks() || getModel().getShowCFG()) { @@ -1403,6 +1631,27 @@ private void updateVisibleFigureWidgets() { } } + private void updateVisibleLiveRangeWidgets() { + if (getModel().getShowCFG() && getModel().getShowLiveRanges()) { + for (LiveRangeSegment segment : getModel().getDiagram().getLiveRangeSegments()) { + LiveRangeWidget liveRangeWidget = getWidget(segment); + boolean visible = true; + for (InputNode n : getModel().getDiagram().getInputGraph().getRelatedNodes(segment.getLiveRange().getId())) { + if (!getModel().getDiagram().hasFigure(n)) { + visible = false; + break; + } + FigureWidget f = getWidget(getModel().getDiagram().getFigure(n)); + if (!f.isVisible()) { + visible = false; + break; + } + } + liveRangeWidget.setVisible(visible); + } + } + } + private void updateNodeHull() { if (getModel().getShowNodeHull()) { List boundaries = new ArrayList<>(); @@ -1433,6 +1682,23 @@ private void updateNodeHull() { } } + private void updateLiveRangeWidgetLocations(Set oldVisibleLiveRangeWidgets) { + if (getModel().getShowCFG() && getModel().getShowLiveRanges()) { + boolean doAnimation = shouldAnimate(); + for (LiveRangeSegment segment : getModel().getDiagram().getLiveRangeSegments()) { + LiveRangeWidget liveRangeWidget = getWidget(segment); + if (liveRangeWidget.isVisible()) { + Point location = new Point(segment.getStartPoint()); + if (doAnimation && oldVisibleLiveRangeWidgets.contains(liveRangeWidget)) { + getSceneAnimator().animatePreferredLocation(liveRangeWidget, location); + } else { + liveRangeWidget.setPreferredLocation(location); + } + } + } + } + } + private void updateVisibleBlockWidgets() { if (getModel().getShowBlocks() || getModel().getShowCFG()) { Set visibleBlocks = new HashSet<>(); @@ -1442,6 +1708,12 @@ private void updateVisibleBlockWidgets() { visibleBlocks.add(figure.getBlock()); } } + for (LiveRangeSegment segment : getModel().getDiagram().getLiveRangeSegments()) { + LiveRangeWidget liveRangeWidget = getWidget(segment); + if (liveRangeWidget != null && liveRangeWidget.isVisible()) { + visibleBlocks.add(segment.getCluster()); + } + } if (getModel().getShowCFG() && getModel().getShowEmptyBlocks()) { // Add remaining blocks. visibleBlocks.addAll(getModel().getDiagram().getBlocks()); @@ -1463,6 +1735,22 @@ private void updateVisibleBlockWidgets() { !(getModel().getShowCFG() && (block.getInputBlock().isArtificial() || block.getInputBlock().getNodes().isEmpty())); BlockWidget blockWidget = getWidget(block); blockWidget.setVisible(visibleAfter); + + // Update node width for live range layout. + int nodeWidth = ClusterNode.EMPTY_BLOCK_LIVE_RANGE_X_OFFSET; + for (InputNode n : block.getInputBlock().getNodes()) { + if (!getModel().getDiagram().hasFigure(n)) { + // n might not be visible (e.g. filtered out). + continue; + } + Figure f = getModel().getDiagram().getFigure(n); + FigureWidget figureWidget = getWidget(f); + if (figureWidget != null && figureWidget.isVisible()) { + nodeWidth = f.getWidth(); + break; + } + } + blockWidget.setNodeWidth(nodeWidth); } } } @@ -1509,6 +1797,16 @@ private HashSet getVisibleConnections() { return visibleConnections; } + private List getVisibleLiveRangeSegments() { + List visibleLiveRangeSegments = new ArrayList<>(); + for (LiveRangeSegment segment : getModel().getDiagram().getLiveRangeSegments()) { + if (isVisibleLiveRangeSegment(segment)) { + visibleLiveRangeSegments.add(segment); + } + } + return visibleLiveRangeSegments; + } + private void updateFigureWidgetLocations(Set oldVisibleFigureWidgets) { boolean doAnimation = shouldAnimate(); for (Figure figure : getModel().getDiagram().getFigures()) { @@ -1541,6 +1839,33 @@ private void updateBlockWidgetBounds(Set oldVisibleBlockWidgets) { } } + private void updateLiveRangeIdsInBlockWidgets() { + for (Block block : getModel().getDiagram().getBlocks()) { + BlockWidget blockWidget = getWidget(block); + if (blockWidget != null && blockWidget.isVisible()) { + List liveRangeIds = new ArrayList<>(); + for (Integer liveRangeId : block.getLiveRangeIds()) { + if (isVisibleLiveRange(liveRangeId)) { + liveRangeIds.add(liveRangeId); + } + } + blockWidget.setLiveRangeIds(liveRangeIds); + } + } + } + + private void repaintLiveRangeWidgets() { + for (LiveRangeSegment segment : getModel().getDiagram().getLiveRangeSegments()) { + LiveRangeWidget liveRangeWidget = getWidget(segment); + if (liveRangeWidget.isVisible()) { + assert segment.getStartPoint().x == segment.getEndPoint().x; + int length = segment.getEndPoint().y - segment.getStartPoint().y; + liveRangeWidget.setLength(length); + liveRangeWidget.repaint(); + } + } + } + public JPopupMenu createPopupMenu() { JPopupMenu menu = new JPopupMenu(); diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramViewModel.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramViewModel.java index 710c5c125f61a..8e81c522503d0 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramViewModel.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramViewModel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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 @@ import com.sun.hotspot.igv.data.Properties; import com.sun.hotspot.igv.data.*; +import com.sun.hotspot.igv.data.services.PreProcessor; import com.sun.hotspot.igv.data.services.Scheduler; import com.sun.hotspot.igv.difference.Difference; import com.sun.hotspot.igv.filter.ColorFilter; @@ -33,6 +34,7 @@ import com.sun.hotspot.igv.filter.FilterChainProvider; import com.sun.hotspot.igv.graph.Diagram; import com.sun.hotspot.igv.graph.Figure; +import com.sun.hotspot.igv.graph.LiveRangeSegment; import com.sun.hotspot.igv.graph.MatcherSelector; import com.sun.hotspot.igv.settings.Settings; import com.sun.hotspot.igv.util.RangeSliderModel; @@ -53,6 +55,7 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene private ArrayList graphs; private Set hiddenNodes; private Set selectedNodes; + private Set selectedLiveRanges; private FilterChain filterChain; private final FilterChain customFilterChain; private final FilterChain filtersOrder; @@ -60,7 +63,8 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene private InputGraph cachedInputGraph; private final ChangedEvent diagramChangedEvent = new ChangedEvent<>(this); private final ChangedEvent graphChangedEvent = new ChangedEvent<>(this); - private final ChangedEvent selectedNodesChangedEvent = new ChangedEvent<>(this); + // This event signals a change in the selection of nodes and/or live ranges. + private final ChangedEvent selectedElementsChangedEvent = new ChangedEvent<>(this); private final ChangedEvent hiddenNodesChangedEvent = new ChangedEvent<>(this); private ChangedListener titleChangedListener = g -> {}; private boolean showFreeInteractive; @@ -70,6 +74,7 @@ public class DiagramViewModel extends RangeSliderModel implements ChangedListene private boolean showCFG; private boolean showNodeHull; private boolean showEmptyBlocks; + private boolean showLiveRanges; private static boolean globalSelection = false; private static boolean cutEdges = false; @@ -112,6 +117,7 @@ public boolean getShowFreeInteractive() { public void setShowFreeInteractive(boolean enable) { showFreeInteractive = enable; if (enable) { + selectedLiveRanges.clear(); diagramChangedEvent.fire(); } } @@ -123,6 +129,7 @@ public boolean getShowStableSea() { public void setShowStableSea(boolean enable) { showStableSea = enable; if (enable) { + selectedLiveRanges.clear(); diagramChangedEvent.fire(); } } @@ -134,6 +141,7 @@ public boolean getShowSea() { public void setShowSea(boolean enable) { showSea = enable; if (enable) { + selectedLiveRanges.clear(); diagramChangedEvent.fire(); } } @@ -145,6 +153,7 @@ public boolean getShowBlocks() { public void setShowBlocks(boolean enable) { showBlocks = enable; if (enable) { + selectedLiveRanges.clear(); diagramChangedEvent.fire(); } } @@ -179,6 +188,18 @@ public void setShowEmptyBlocks(boolean b) { diagramChangedEvent.fire(); } + public boolean getShowLiveRanges() { + return showLiveRanges; + } + + public void setShowLiveRanges(boolean b) { + showLiveRanges = b; + if (!showLiveRanges) { + selectedLiveRanges.clear(); + } + diagramChangedEvent.fire(); + } + private void initGroup() { group.getChangedEvent().addListener(g -> { assert g == group; @@ -218,9 +239,11 @@ public DiagramViewModel(DiagramViewModel model) { showBlocks = model.getShowBlocks(); showNodeHull = model.getShowNodeHull(); showEmptyBlocks = model.getShowEmptyBlocks(); + showLiveRanges = model.getShowLiveRanges(); hiddenNodes = new HashSet<>(model.getHiddenNodes()); selectedNodes = new HashSet<>(); + selectedLiveRanges = new HashSet<>(); changed(this); } @@ -243,9 +266,11 @@ public DiagramViewModel(InputGraph graph) { showCFG = Settings.get().getInt(Settings.DEFAULT_VIEW, Settings.DEFAULT_VIEW_DEFAULT) == Settings.DefaultView.CONTROL_FLOW_GRAPH; showNodeHull = true; showEmptyBlocks = true; + showLiveRanges = true; hiddenNodes = new HashSet<>(); selectedNodes = new HashSet<>(); + selectedLiveRanges = new HashSet<>(); selectGraph(graph); } @@ -257,8 +282,8 @@ public ChangedEvent getGraphChangedEvent() { return graphChangedEvent; } - public ChangedEvent getSelectedNodesChangedEvent() { - return selectedNodesChangedEvent; + public ChangedEvent getSelectedElementsChangedEvent() { + return selectedElementsChangedEvent; } public ChangedEvent getHiddenNodesChangedEvent() { @@ -311,7 +336,16 @@ public void setSelectedNodes(Set nodes) { } } setColors(colors); - selectedNodesChangedEvent.fire(); + selectedElementsChangedEvent.fire(); + } + + public Set getSelectedLiveRanges() { + return selectedLiveRanges; + } + + public void setSelectedLiveRanges(Set liveRanges) { + selectedLiveRanges = liveRanges; + selectedElementsChangedEvent.fire(); } public void showFigures(Collection
figures) { @@ -336,6 +370,16 @@ public Set
getSelectedFigures() { return result; } + public Set getSelectedLiveRangeSegments() { + Set result = new HashSet<>(); + for (LiveRangeSegment segment : diagram.getLiveRangeSegments()) { + if (getSelectedLiveRanges().contains(segment.getLiveRange().getId())) { + result.add(segment); + } + } + return result; + } + public void showOnly(final Set nodes) { final HashSet allNodes = new HashSet<>(getGroup().getAllNodes()); allNodes.removeAll(nodes); @@ -398,6 +442,8 @@ private void rebuildDiagram() { s.schedule(graph); graph.ensureNodesInBlocks(); } + PreProcessor p = Lookup.getDefault().lookup(PreProcessor.class); + p.preProcess(graph); diagram = new Diagram(graph, Settings.get().get(Settings.NODE_TEXT, Settings.NODE_TEXT_DEFAULT), Settings.get().get(Settings.NODE_SHORT_TEXT, Settings.NODE_SHORT_TEXT_DEFAULT), diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramViewer.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramViewer.java index e8cfd2968dc29..26c69a4488c83 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramViewer.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/DiagramViewer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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.ChangedEvent; +import com.sun.hotspot.igv.data.InputLiveRange; import com.sun.hotspot.igv.data.InputNode; import java.awt.*; import java.util.Collection; @@ -77,9 +78,15 @@ enum InteractionMode { void centerSelectedFigures(); + void centerSelectedLiveRanges(); + void addSelectedNodes(Collection nodes, boolean showIfHidden); - void clearSelectedNodes(); + void addSelectedLiveRanges(Collection liveRanges, boolean showIfHidden); + + void addSelectedElements(Collection nodes, Collection liveRanges, boolean showIfHidden); + + void clearSelectedElements(); void setInteractionMode(InteractionMode mode); diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/EditorInputGraphProvider.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/EditorInputGraphProvider.java index ade73d9f1e5cb..2ff4b20f038f6 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/EditorInputGraphProvider.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/EditorInputGraphProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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 @@ -73,9 +73,9 @@ public void addSelectedNodes(Collection nodes, boolean showIfHidden) } @Override - public void clearSelectedNodes() { + public void clearSelectedElements() { if (editor != null && EditorTopComponent.isOpen(editor)) { - editor.clearSelectedNodes(); + editor.clearSelectedElements(); editor.requestActive(); } } diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/EditorTopComponent.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/EditorTopComponent.java index ff51b8928f676..35e440322d870 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/EditorTopComponent.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/EditorTopComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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 @@ import com.sun.hotspot.igv.data.GraphDocument; import com.sun.hotspot.igv.data.Group; import com.sun.hotspot.igv.data.InputGraph; +import com.sun.hotspot.igv.data.InputLiveRange; import com.sun.hotspot.igv.data.InputNode; import com.sun.hotspot.igv.data.services.InputGraphProvider; import com.sun.hotspot.igv.graph.Figure; @@ -205,6 +206,7 @@ public void mouseMoved(MouseEvent e) {} toolBar.addSeparator(); toolBar.add(new JToggleButton(new PredSuccAction(diagramViewModel.getShowNodeHull()))); toolBar.add(new JToggleButton(new ShowEmptyBlocksAction(cfgLayoutAction, diagramViewModel.getShowEmptyBlocks()))); + toolBar.add(new JToggleButton(new ShowLiveRangesAction(cfgLayoutAction, diagramViewModel.getShowLiveRanges()))); toolBar.addSeparator(); UndoAction undoAction = UndoAction.get(UndoAction.class); @@ -353,12 +355,26 @@ public void colorSelectedFigures(Color color) { scene.colorSelectedFigures(color); } + public void addSelectedLiveRanges(Collection liveRanges, boolean showIfHidden) { + scene.addSelectedLiveRanges(liveRanges, showIfHidden); + } + + public void addSelectedElements(Collection nodes, + Collection liveRanges, + boolean showIfHidden) { + scene.addSelectedElements(nodes, liveRanges, showIfHidden); + } + public void centerSelectedNodes() { scene.centerSelectedFigures(); } - public void clearSelectedNodes() { - scene.clearSelectedNodes(); + public void centerSelectedLiveRanges() { + scene.centerSelectedLiveRanges(); + } + + public void clearSelectedElements() { + scene.clearSelectedElements(); } public Rectangle getSceneBounds() { @@ -450,7 +466,11 @@ public TopComponent cloneComponent() { for (Figure figure : getModel().getSelectedFigures()) { selectedNodes.add(figure.getInputNode()); } - etc.addSelectedNodes(selectedNodes, false); + Set selectedLiveRanges = new HashSet<>(); + for (int liveRangeId : getModel().getSelectedLiveRanges()) { + selectedLiveRanges.add(getModel().getGraph().getLiveRange(liveRangeId)); + } + etc.addSelectedElements(selectedNodes, selectedLiveRanges, false); model.setGlobalSelection(GlobalSelectionAction.get(GlobalSelectionAction.class).isSelected(), false); model.setCutEdges(CutEdgesAction.get(CutEdgesAction.class).isSelected(), false); etc.resetUndoRedo(); diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/LiveRangeQuickSearch.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/LiveRangeQuickSearch.java new file mode 100644 index 0000000000000..bfa3900a6488d --- /dev/null +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/LiveRangeQuickSearch.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025, 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.InputLiveRange; +import java.util.*; + +public class LiveRangeQuickSearch extends SimpleQuickSearch { + + @Override + String prefix() { + return "L"; + } + + @Override + String id(Object entity) { + assert entity instanceof InputLiveRange; + return Integer.toString(((InputLiveRange)entity).getId()); + } + + @Override + Collection getAllEntities(InputGraph inputGraph) { + return new ArrayList<>(inputGraph.getLiveRanges()); + } + + @Override + void selectEntity(EditorTopComponent editor, Object entity) { + assert entity instanceof InputLiveRange; + Set entitySingleton = new HashSet<>(); + entitySingleton.add((InputLiveRange)entity); + editor.addSelectedLiveRanges(entitySingleton, true); + editor.centerSelectedLiveRanges(); + } +} diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/NodeQuickSearch.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/NodeQuickSearch.java index fb8ef8535b765..254b8ca15efec 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/NodeQuickSearch.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/NodeQuickSearch.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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 @@ -121,7 +121,7 @@ public void evaluate(SearchRequest request, SearchResponse response) { if (theGraph != null) { editor.getModel().selectGraph(theGraph); } - editor.clearSelectedNodes(); + editor.clearSelectedElements(); editor.addSelectedNodes(nodeSet, true); editor.centerSelectedNodes(); editor.requestActive(); @@ -151,7 +151,7 @@ public void run() { if (theGraph != null) { editor.getModel().selectGraph(theGraph); } - editor.clearSelectedNodes(); + editor.clearSelectedElements(); editor.addSelectedNodes(tmpSet, true); editor.centerSelectedNodes(); editor.requestActive(); diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/SimpleQuickSearch.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/SimpleQuickSearch.java new file mode 100644 index 0000000000000..ab3c439ad3a68 --- /dev/null +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/SimpleQuickSearch.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2025, 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.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.ArrayList; +import java.util.Collection; +import java.util.List; +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 abstract class SimpleQuickSearch implements SearchProvider { + + abstract String prefix(); + + abstract String id(Object entity); + + abstract Collection getAllEntities(InputGraph inputGraph); + + abstract void selectEntity(EditorTopComponent editor, Object entity); + + @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 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((Object a, Object b) -> + compareByRankThenNumVal(rawValue, + prefix() + id(a), + prefix() + id(b))); + + final InputGraph theGraph = p.getGraph() != matchGraph ? matchGraph : null; + for (final Object entity : matches) { + if (!response.addResult(() -> { + final EditorTopComponent editor = EditorTopComponent.getActive(); + assert(editor != null); + if (theGraph != null) { + editor.getModel().selectGraph(theGraph); + } + editor.clearSelectedElements(); + selectEntity(editor, entity); + editor.requestActive(); + }, + prefix() + id(entity) + (theGraph != null ? " in " + theGraph.getName() : ""))) { + return; + } + } + } + } + + private List findMatches(String entityName, InputGraph inputGraph, SearchResponse response) { + try { + RegexpPropertyMatcher matcher = new RegexpPropertyMatcher("", entityName, Pattern.CASE_INSENSITIVE); + List matches = new ArrayList<>(); + for (Object entity : getAllEntities(inputGraph)) { + if (matcher.match(prefix() + id(entity))) { + matches.add(entity); + } + } + 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 l1, String l2) { + int key1 = StringUtils.rankMatch(qry, l1); + int key2 = StringUtils.rankMatch(qry, l2); + if (key1 == key2) { + // If the matches have the same rank, compare the numeric values of + // their first words, if applicable. + try { + key1 = Integer.parseInt(l1.replace(prefix(), "")); + key2 = Integer.parseInt(l2.replace(prefix(), "")); + } catch (Exception e) { + // Not applicable, return equality value. + return 0; + } + } + return Integer.compare(key1, key2); + } + +} diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ExpandAdjacentAction.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ExpandAdjacentAction.java index daceaa708bd97..ce37b4b8e1d3b 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ExpandAdjacentAction.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ExpandAdjacentAction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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,16 +24,16 @@ package com.sun.hotspot.igv.view.actions; import com.sun.hotspot.igv.graph.Figure; +import com.sun.hotspot.igv.view.DiagramViewModel; import com.sun.hotspot.igv.view.EditorTopComponent; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.Function; import org.openide.util.HelpCtx; -import org.openide.util.actions.CallableSystemAction; -public abstract class ExpandAdjacentAction extends CallableSystemAction { +public abstract class ExpandAdjacentAction extends ModelAwareAction { protected void expandFigures(Function> getAdjacentFigures) { EditorTopComponent editor = EditorTopComponent.getActive(); @@ -47,10 +47,13 @@ protected void expandFigures(Function> getAdjacentFigures) } } - public abstract void performAction(); - public abstract String getName(); + @Override + public boolean isEnabled(DiagramViewModel model) { + return model != null && !model.getSelectedNodes().isEmpty(); + } + @Override public HelpCtx getHelpCtx() { return HelpCtx.DEFAULT_HELP; diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ExpandPredecessorsAction.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ExpandPredecessorsAction.java index 481bb58aef54d..e8520004b25cc 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ExpandPredecessorsAction.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ExpandPredecessorsAction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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,6 +24,7 @@ package com.sun.hotspot.igv.view.actions; import com.sun.hotspot.igv.graph.Figure; +import com.sun.hotspot.igv.view.DiagramViewModel; /** * @@ -32,7 +33,7 @@ public final class ExpandPredecessorsAction extends ExpandAdjacentAction { @Override - public void performAction() { + public void performAction(DiagramViewModel model) { expandFigures(Figure::getPredecessors); } @@ -40,4 +41,9 @@ public void performAction() { public String getName() { return "Expand Above"; } + + @Override + public String getDescription() { + return "Expand predecessors of current set of selected nodes"; + } } diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ExpandSuccessorsAction.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ExpandSuccessorsAction.java index 340a2d400d3b9..c89924a5b45e7 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ExpandSuccessorsAction.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ExpandSuccessorsAction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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,6 +24,7 @@ package com.sun.hotspot.igv.view.actions; import com.sun.hotspot.igv.graph.Figure; +import com.sun.hotspot.igv.view.DiagramViewModel; /** * @@ -32,7 +33,7 @@ public final class ExpandSuccessorsAction extends ExpandAdjacentAction { @Override - public void performAction() { + public void performAction(DiagramViewModel model) { expandFigures(Figure::getSuccessors); } @@ -40,4 +41,9 @@ public void performAction() { public String getName() { return "Expand Below"; } + + @Override + public String getDescription() { + return "Expand successors of current set of selected nodes"; + } } diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ExtractAction.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ExtractAction.java index 24547b19b6a30..d9a198ee951d8 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ExtractAction.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ExtractAction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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,11 @@ */ package com.sun.hotspot.igv.view.actions; +import java.util.HashSet; +import java.util.Set; + +import com.sun.hotspot.igv.data.InputGraph; +import com.sun.hotspot.igv.data.InputNode; import com.sun.hotspot.igv.view.DiagramViewModel; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; @@ -43,7 +48,7 @@ }) @Messages({ "CTL_ExtractAction=Extract", - "HINT_ExtractAction=Extract current set of selected nodes" + "HINT_ExtractAction=Extract selected nodes and live ranges" }) public final class ExtractAction extends ModelAwareAction { @@ -64,11 +69,19 @@ public String getName() { @Override public void performAction(DiagramViewModel model) { - model.showOnly(model.getSelectedNodes()); + Set nodes = new HashSet<>(model.getSelectedNodes()); + InputGraph graph = model.getDiagram().getInputGraph(); + for (int liveRangeId : model.getSelectedLiveRanges()) { + for (InputNode node : graph.getRelatedNodes(liveRangeId)) { + nodes.add(node.getId()); + } + } + model.showOnly(nodes); } @Override public boolean isEnabled(DiagramViewModel model) { - return model != null && !model.getSelectedNodes().isEmpty(); + return model != null && + !(model.getSelectedNodes().isEmpty() && model.getSelectedLiveRanges().isEmpty()); } } diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/HideAction.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/HideAction.java index cac2d167426cd..9a4b0bfc45c7b 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/HideAction.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/HideAction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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,8 @@ */ package com.sun.hotspot.igv.view.actions; +import com.sun.hotspot.igv.data.InputGraph; +import com.sun.hotspot.igv.data.InputNode; import com.sun.hotspot.igv.view.DiagramViewModel; import java.util.HashSet; import java.util.Set; @@ -44,8 +46,8 @@ @ActionReference(path = "Shortcuts", name = "D-H") }) @Messages({ - "CTL_HideAction=Hide nodes", - "HINT_HideAction=Hide selected nodes" + "CTL_HideAction=Hide", + "HINT_HideAction=Hide selected nodes and live ranges" }) public final class HideAction extends ModelAwareAction { @@ -69,11 +71,18 @@ public void performAction(DiagramViewModel model) { Set selectedNodes = model.getSelectedNodes(); HashSet nodes = new HashSet<>(model.getHiddenNodes()); nodes.addAll(selectedNodes); + InputGraph graph = model.getDiagram().getInputGraph(); + for (int liveRangeId : model.getSelectedLiveRanges()) { + for (InputNode node : graph.getRelatedNodes(liveRangeId)) { + nodes.add(node.getId()); + } + } model.setHiddenNodes(nodes); } @Override public boolean isEnabled(DiagramViewModel model) { - return model != null && !model.getSelectedNodes().isEmpty(); + return model != null && + !(model.getSelectedNodes().isEmpty() && model.getSelectedLiveRanges().isEmpty()); } } diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ModelAwareAction.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ModelAwareAction.java index ce373436d9395..4de588f6357a3 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ModelAwareAction.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ModelAwareAction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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 @@ -37,8 +37,6 @@ public ModelAwareAction() { putValue(Action.SHORT_DESCRIPTION, getDescription()); } - protected abstract String iconResource(); - protected abstract String getDescription(); public abstract String getName(); @@ -54,7 +52,7 @@ public Class contextClass() { @Override public void addContextListener(DiagramViewModel model) { - model.getSelectedNodesChangedEvent().addListener(this); + model.getSelectedElementsChangedEvent().addListener(this); model.getDiagramChangedEvent().addListener(this); model.getGraphChangedEvent().addListener(this); model.getHiddenNodesChangedEvent().addListener(this); @@ -62,7 +60,7 @@ public void addContextListener(DiagramViewModel model) { @Override public void removeContextListener(DiagramViewModel model) { - model.getSelectedNodesChangedEvent().removeListener(this); + model.getSelectedElementsChangedEvent().removeListener(this); model.getDiagramChangedEvent().removeListener(this); model.getGraphChangedEvent().removeListener(this); model.getHiddenNodesChangedEvent().removeListener(this); diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ShowLiveRangesAction.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ShowLiveRangesAction.java new file mode 100644 index 0000000000000..8910f0c0635f7 --- /dev/null +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/actions/ShowLiveRangesAction.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2025, 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 com.sun.hotspot.igv.view.EditorTopComponent; +import java.awt.event.ActionEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import javax.swing.AbstractAction; +import javax.swing.ImageIcon; +import org.openide.util.ImageUtilities; + +public class ShowLiveRangesAction extends AbstractAction implements PropertyChangeListener { + + private boolean selected; + private AbstractAction parentAction; + + public ShowLiveRangesAction(AbstractAction action, boolean select) { + this.parentAction = action; + this.selected = select; + this.parentAction.addPropertyChangeListener(this); + putValue(SELECTED_KEY, this.selected); + putValue(SMALL_ICON, new ImageIcon(ImageUtilities.loadImage(iconResource()))); + putValue(SHORT_DESCRIPTION, "Show live ranges in control-flow graph view (if liveness information is available)"); + enableIfParentSelected(); + } + + @Override + public void actionPerformed(ActionEvent ev) { + this.selected = isSelected(); + EditorTopComponent editor = EditorTopComponent.getActive(); + if (editor != null) { + editor.getModel().setShowLiveRanges(this.selected); + } + } + + protected String iconResource() { + return "com/sun/hotspot/igv/view/images/showLiveRanges.png"; + } + + private boolean isSelected() { + return (Boolean)getValue(SELECTED_KEY); + } + + private void enableIfParentSelected() { + boolean enable = parentAction.isEnabled() && (Boolean)parentAction.getValue(SELECTED_KEY); + if (enable != this.isEnabled()) { + if (enable) { + putValue(SELECTED_KEY, this.selected); + } else { + this.selected = isSelected(); + putValue(SELECTED_KEY, false); + } + } + this.setEnabled(enable); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getSource() == this.parentAction) { + enableIfParentSelected(); + } + } +} diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/widgets/BlockWidget.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/widgets/BlockWidget.java index 941836f5bb703..5e6e80d31b77f 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/widgets/BlockWidget.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/widgets/BlockWidget.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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,6 +31,7 @@ import java.awt.*; import java.awt.event.MouseEvent; import java.awt.geom.Rectangle2D; +import java.util.List; import org.netbeans.api.visual.action.WidgetAction; import org.netbeans.api.visual.widget.Scene; import org.netbeans.api.visual.widget.Widget; @@ -46,6 +47,10 @@ public class BlockWidget extends Widget implements DoubleClickHandler { private static final Font TITLE_FONT = new Font("Arial", Font.BOLD, 14); public static final Color TITLE_COLOR = new Color(42, 42, 171); private final Block block; + private static final Font LIVE_RANGE_FONT = new Font("Arial", Font.BOLD, 12); + public static final Color LIVE_RANGE_COLOR = Color.BLACK; + private int nodeWidth; + private List liveRangeIds; public BlockWidget(Scene scene, Block block) { super(scene); @@ -55,6 +60,14 @@ public BlockWidget(Scene scene, Block block) { this.setCheckClipping(true); } + public void setLiveRangeIds(List liveRangeIds) { + this.liveRangeIds = liveRangeIds; + } + + public void setNodeWidth(int nodeWidth) { + this.nodeWidth = nodeWidth; + } + @Override protected void paintWidget() { super.paintWidget(); @@ -75,6 +88,19 @@ protected void paintWidget() { String s = "B" + getBlockNode().getName(); Rectangle2D r1 = g.getFontMetrics().getStringBounds(s, g); g.drawString(s, r.x + 5, r.y + (int) r1.getHeight()); + + g.setColor(LIVE_RANGE_COLOR); + g.setFont(LIVE_RANGE_FONT); + if (liveRangeIds != null) { + int x = nodeWidth + block.getLiveRangeSeparation(); + for (int liveRangeId : liveRangeIds) { + String ls = "L" + String.valueOf(liveRangeId); + Rectangle2D lr = g.getFontMetrics().getStringBounds(ls, g); + g.drawString(ls, r.x + x, r.y + (int) lr.getHeight() + 2); + x += block.getLiveRangeSeparation(); + } + } + g.setStroke(old); } @@ -82,7 +108,7 @@ private void addToSelection(BlockWidget blockWidget, boolean additiveSelection) InputGraphProvider graphProvider = LookupHistory.getLast(InputGraphProvider.class); if (graphProvider != null) { if (!additiveSelection) { - graphProvider.clearSelectedNodes(); + graphProvider.clearSelectedElements(); } graphProvider.addSelectedNodes(blockWidget.getBlockNode().getNodes(), false); } diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/widgets/FigureWidget.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/widgets/FigureWidget.java index 5578c4505cf29..8d71249479a2c 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/widgets/FigureWidget.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/widgets/FigureWidget.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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,13 @@ */ package com.sun.hotspot.igv.view.widgets; +import com.sun.hotspot.igv.data.InputGraph; +import com.sun.hotspot.igv.data.InputLiveRange; +import com.sun.hotspot.igv.data.LivenessInfo; import com.sun.hotspot.igv.data.Properties; import com.sun.hotspot.igv.graph.Diagram; import com.sun.hotspot.igv.graph.Figure; +import com.sun.hotspot.igv.graph.LiveRangeSegment; import com.sun.hotspot.igv.graph.Slot; import com.sun.hotspot.igv.util.DoubleClickAction; import com.sun.hotspot.igv.util.DoubleClickHandler; @@ -317,6 +321,47 @@ public JPopupMenu getPopupMenu(Widget widget, Point point) { menu.addSeparator(); build(menu, getFigure(), this, true, diagramScene); + if (diagramScene.getModel().getShowCFG() && + diagramScene.getModel().getShowLiveRanges()) { + InputGraph graph = diagramScene.getModel().getGraph(); + LivenessInfo l = graph.getLivenessInfoForNode(getFigure().getInputNode()); + if (l != null) { + Set liveRanges = new HashSet<>(); + if (l.def != null) { + liveRanges.add(graph.getLiveRange(l.def)); + } + if (l.use != null) { + for (int use : l.use) { + liveRanges.add(graph.getLiveRange(use)); + } + } + if (l.join != null) { + for (int join : l.join) { + liveRanges.add(graph.getLiveRange(join)); + } + } + if (!liveRanges.isEmpty()) { + menu.addSeparator(); + menu.add(diagramScene.createGotoLiveRangeAction("Select live ranges", liveRanges)); + menu.addSeparator(); + if (l.def != null) { + menu.add(diagramScene.createGotoLiveRangeAction(graph.getLiveRange(l.def))); + } + menu.addSeparator(); + if (l.use != null) { + for (int use : l.use) { + menu.add(diagramScene.createGotoLiveRangeAction(graph.getLiveRange(use))); + } + } + if (l.join != null) { + for (int join : l.join) { + menu.add(diagramScene.createGotoLiveRangeAction(graph.getLiveRange(join))); + } + } + } + } + } + return menu; } diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/widgets/LiveRangeWidget.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/widgets/LiveRangeWidget.java new file mode 100644 index 0000000000000..82e496b60ab67 --- /dev/null +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/widgets/LiveRangeWidget.java @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2025, 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.widgets; + +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.graph.Diagram; +import com.sun.hotspot.igv.graph.Figure; +import com.sun.hotspot.igv.graph.LiveRangeSegment; +import com.sun.hotspot.igv.util.DoubleClickAction; +import com.sun.hotspot.igv.util.DoubleClickHandler; +import com.sun.hotspot.igv.util.PropertiesConverter; +import com.sun.hotspot.igv.util.PropertiesSheet; +import com.sun.hotspot.igv.view.DiagramScene; +import com.sun.hotspot.igv.view.DiagramViewModel; +import com.sun.hotspot.igv.view.actions.CustomSelectAction; + +import java.awt.*; +import java.util.HashSet; +import java.util.Set; +import javax.swing.JPopupMenu; +import org.netbeans.api.visual.action.ActionFactory; +import org.netbeans.api.visual.action.PopupMenuProvider; +import org.netbeans.api.visual.action.SelectProvider; +import org.netbeans.api.visual.action.WidgetAction; +import org.netbeans.api.visual.model.ObjectState; +import org.netbeans.api.visual.widget.Widget; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.openide.nodes.Sheet; + +public class LiveRangeWidget extends Widget implements Properties.Provider, PopupMenuProvider, DoubleClickHandler { + + private final LiveRangeSegment liveRangeSegment; + private final DiagramScene scene; + private int length; + private Rectangle clientArea; + private final Node node; + private static final float NORMAL_THICKNESS = 1.4f; + private static final float SELECTED_THICKNESS = 2.2f; + private boolean highlighted; + private static final Color HIGHLIGHTED_COLOR = Color.BLUE; + + private static final int RANGE_WIDTH = 4; + + public LiveRangeWidget(LiveRangeSegment liveRangeSegment, DiagramScene scene, int length) { + super(scene); + this.liveRangeSegment = liveRangeSegment; + this.scene = scene; + this.length = length; + + getActions().addAction(new DoubleClickAction(this)); + getActions().addAction(ActionFactory.createPopupMenuAction(this)); + + updateClientArea(); + + // Initialize node for property sheet + node = new AbstractNode(Children.LEAF) { + @Override + protected Sheet createSheet() { + Sheet s = super.createSheet(); + PropertiesSheet.initializeSheet(liveRangeSegment.getProperties(), s); + return s; + } + }; + node.setDisplayName("L" + liveRangeSegment.getLiveRange().getId()); + + this.setToolTipText(PropertiesConverter.convertToHTML(liveRangeSegment.getProperties())); + getActions().addAction(new CustomSelectAction(new SelectProvider() { + @Override + public boolean isAimingAllowed(Widget widget, Point localLocation, boolean invertSelection) { + return true; + } + + @Override + public boolean isSelectionAllowed(Widget widget, Point localLocation, boolean invertSelection) { + return true; + } + + @Override + public void select(Widget widget, Point localLocation, boolean invertSelection) { + scene.userSelectionSuggested(liveRangeSegment.getSegmentSet(), invertSelection); + } + })); + } + + public void setLength(int length) { + this.length = length; + updateClientArea(); + } + + private void updateClientArea() { + clientArea = new Rectangle(RANGE_WIDTH * 2, length); + clientArea.grow(RANGE_WIDTH * 2, RANGE_WIDTH * 2); + } + + @Override + protected Rectangle calculateClientArea() { + return clientArea; + } + + @Override + protected void paintWidget() { + if (scene.getZoomFactor() < 0.1) { + return; + } + Graphics2D g = getScene().getGraphics(); + g.setPaint(this.getBackground()); + boolean selected = scene.getSelectedObjects().contains(liveRangeSegment); + g.setStroke(new BasicStroke(selected ? SELECTED_THICKNESS : NORMAL_THICKNESS)); + g.setColor(highlighted ? HIGHLIGHTED_COLOR : liveRangeSegment.getColor()); + if (highlighted) { + g.setStroke(new BasicStroke(2)); + } + int start = 0; + int end = length; + if (length == 0 && !liveRangeSegment.isInstantaneous()) { + // Continuation segment in empty basic block. + assert liveRangeSegment.getStart() == null && liveRangeSegment.getEnd() == null; + start = -2; + end = 3; + } + g.drawLine(0, start, 0, end); + if (liveRangeSegment.isOpening()) { + g.drawLine(-RANGE_WIDTH, 0, RANGE_WIDTH, 0); + } + if (liveRangeSegment.isClosing()) { + g.drawLine(-RANGE_WIDTH, end, RANGE_WIDTH, end); + } + } + + @Override + protected void notifyStateChanged(ObjectState previousState, ObjectState state) { + super.notifyStateChanged(previousState, state); + if (previousState.isHighlighted() != state.isHighlighted()) { + for (LiveRangeSegment segment : liveRangeSegment.getSegmentSet()) { + LiveRangeWidget figureWidget = scene.getWidget(segment); + figureWidget.highlighted = state.isHighlighted(); + figureWidget.revalidate(true); + } + } + } + + @Override + public JPopupMenu getPopupMenu(Widget widget, Point point) { + Diagram diagram = this.scene.getModel().getDiagram(); + InputGraph graph = diagram.getInputGraph(); + int liveRangeId = liveRangeSegment.getLiveRange().getId(); + + JPopupMenu menu = scene.createPopupMenu(); + menu.addSeparator(); + Set
figures = new HashSet<>(); + for (InputNode node : graph.getRelatedNodes(liveRangeId)) { + figures.add((diagram.getFigure(node))); + } + menu.add(scene.createGotoNodesAction("Select nodes", figures)); + menu.addSeparator(); + for (InputNode node : graph.getDefNodes(liveRangeId)) { + menu.add(scene.createGotoAction(diagram.getFigure(node))); + } + menu.addSeparator(); + for (InputNode node : graph.getUseNodes(liveRangeId)) { + menu.add(scene.createGotoAction(diagram.getFigure(node))); + } + return menu; + } + + @Override + public void handleDoubleClick(Widget w, WidgetAction.WidgetMouseEvent e) { + DiagramViewModel model = this.scene.getModel(); + Set nodes = new HashSet<>(); + InputGraph graph = model.getDiagram().getInputGraph(); + int liveRangeId = liveRangeSegment.getLiveRange().getId(); + for (InputNode node : graph.getRelatedNodes(liveRangeId)) { + nodes.add(node.getId()); + } + model.showOnly(nodes); + } + + @Override + public Properties getProperties() { + return liveRangeSegment.getProperties(); + } +} diff --git a/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/images/liveRange.png b/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/images/liveRange.png new file mode 100644 index 0000000000000..b9f06161d8bdb Binary files /dev/null and b/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/images/liveRange.png differ diff --git a/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/images/selectLiveRanges.png b/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/images/selectLiveRanges.png new file mode 100644 index 0000000000000..742856ea422c7 Binary files /dev/null and b/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/images/selectLiveRanges.png differ diff --git a/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/images/selectNodes.png b/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/images/selectNodes.png new file mode 100644 index 0000000000000..73de4eb899362 Binary files /dev/null and b/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/images/selectNodes.png differ diff --git a/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/images/showLiveRanges.png b/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/images/showLiveRanges.png new file mode 100644 index 0000000000000..3f4e9edc5b8e5 Binary files /dev/null and b/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/images/showLiveRanges.png differ diff --git a/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/layer.xml b/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/layer.xml index d50f7c914ccfe..adeb462a2650e 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/layer.xml +++ b/src/utils/IdealGraphVisualizer/View/src/main/resources/com/sun/hotspot/igv/view/layer.xml @@ -14,6 +14,7 @@ + @@ -45,6 +46,11 @@ + + + + +