|
30 | 30 | import java.awt.GridBagLayout;
|
31 | 31 | import java.awt.Insets;
|
32 | 32 | import java.awt.event.ActionEvent;
|
| 33 | +import java.text.NumberFormat; |
33 | 34 | import java.util.ArrayList;
|
34 | 35 | import java.util.Collection;
|
35 | 36 | import java.util.Collections;
|
|
38 | 39 | import java.util.List;
|
39 | 40 | import java.util.Map;
|
40 | 41 | import java.util.Objects;
|
| 42 | +import javax.swing.Icon; |
41 | 43 | import javax.swing.ImageIcon;
|
42 | 44 | import javax.swing.JButton;
|
43 | 45 | import javax.swing.JCheckBoxMenuItem;
|
|
47 | 49 | import javax.swing.SortOrder;
|
48 | 50 | import javax.swing.SwingUtilities;
|
49 | 51 | import org.graalvm.visualvm.heapviewer.HeapContext;
|
| 52 | +import org.graalvm.visualvm.heapviewer.java.ClassNode; |
| 53 | +import org.graalvm.visualvm.heapviewer.java.ClassNodeRenderer; |
50 | 54 | import org.graalvm.visualvm.heapviewer.java.InstanceNode;
|
51 | 55 | import org.graalvm.visualvm.heapviewer.java.InstanceNodeRenderer;
|
52 | 56 | import org.graalvm.visualvm.heapviewer.java.InstanceReferenceNode;
|
|
62 | 66 | import org.graalvm.visualvm.heapviewer.swing.LinkButton;
|
63 | 67 | import org.graalvm.visualvm.heapviewer.ui.HeapViewPlugin;
|
64 | 68 | import org.graalvm.visualvm.heapviewer.ui.HeapViewerActions;
|
| 69 | +import org.graalvm.visualvm.heapviewer.ui.HeapViewerRenderer; |
65 | 70 | import org.graalvm.visualvm.heapviewer.ui.TreeTableView;
|
66 | 71 | import org.graalvm.visualvm.heapviewer.ui.TreeTableViewColumn;
|
67 | 72 | import org.graalvm.visualvm.heapviewer.ui.UIThresholds;
|
|
78 | 83 | import org.graalvm.visualvm.lib.profiler.api.icons.ProfilerIcons;
|
79 | 84 | import org.graalvm.visualvm.lib.ui.UIUtils;
|
80 | 85 | import org.graalvm.visualvm.lib.ui.swing.renderer.LabelRenderer;
|
| 86 | +import org.graalvm.visualvm.lib.ui.swing.renderer.MultiRenderer; |
| 87 | +import org.graalvm.visualvm.lib.ui.swing.renderer.NormalBoldGrayRenderer; |
| 88 | +import org.graalvm.visualvm.lib.ui.swing.renderer.ProfilerRenderer; |
81 | 89 | import org.openide.util.NbBundle;
|
82 | 90 | import org.openide.util.NbPreferences;
|
83 | 91 | import org.openide.util.lookup.ServiceProvider;
|
@@ -375,7 +383,7 @@ private static Collection<HeapViewerNode> computeInstanceRoots(Instance instance
|
375 | 383 | ObjectFieldValue ref = (ObjectFieldValue)reference;
|
376 | 384 | SkipNode snode = HeapPatterns.processGCRootReference(ref);
|
377 | 385 | if (snode != null) {
|
378 |
| - ref = snode.getNextReference(); |
| 386 | + ref = snode.getValue(); |
379 | 387 | nextInstance = ref.getDefiningInstance();
|
380 | 388 | node = snode;
|
381 | 389 | if (firstNode == null) firstNode = node;
|
@@ -622,24 +630,95 @@ public void setChildren(HeapViewerNode[] ch) {
|
622 | 630 |
|
623 | 631 | }
|
624 | 632 |
|
625 |
| - static class SkipNode extends TextNode implements ToRoot { |
| 633 | + static class SkipNode extends FieldToRoot { |
626 | 634 |
|
627 |
| - private ObjectFieldValue reference; |
| 635 | + private int skipped; |
628 | 636 |
|
629 |
| - SkipNode(String text, ObjectFieldValue ref) { |
630 |
| - super(text); |
631 |
| - reference = ref; |
| 637 | + SkipNode(ObjectFieldValue ref, int sk) { |
| 638 | + super(ref); |
| 639 | + skipped = sk; |
632 | 640 | }
|
| 641 | + } |
633 | 642 |
|
634 |
| - public void setChildren(HeapViewerNode[] ch) { |
635 |
| - super.setChildren(ch); |
| 643 | + @NbBundle.Messages({ |
| 644 | + "# {0} - number of skipped nodes", |
| 645 | + "SkipNodeRenderer_Instances=in {0} collapsed instances of " |
| 646 | + }) |
| 647 | + static class SkipNodeRenderer extends MultiRenderer implements HeapViewerRenderer { |
| 648 | + |
| 649 | + private final NormalBoldGrayRenderer nameRenderer; |
| 650 | + private final LabelRenderer equalsRenderer; |
| 651 | + private final ClassNodeRenderer classRenderer; |
| 652 | + private final ProfilerRenderer[] renderers; |
| 653 | + private final Heap heap; |
| 654 | + |
| 655 | + SkipNodeRenderer(Heap heap) { |
| 656 | + this.heap = heap; |
| 657 | + nameRenderer = new NormalBoldGrayRenderer() { |
| 658 | + public void setValue(Object value, int row) { |
| 659 | + SkipNode node = (SkipNode) value; |
| 660 | + String name = node.getFieldName(); |
| 661 | + if (name.startsWith("static ")) { // NOI18N |
| 662 | + setNormalValue("static "); // NOI18N |
| 663 | + setBoldValue(name.substring("static ".length())); // NOI18N |
| 664 | + } else { |
| 665 | + setNormalValue(""); // NOI18N |
| 666 | + setBoldValue(name); |
| 667 | + } |
| 668 | + setIcon(Icons.getIcon(ProfilerIcons.NODE_REVERSE)); |
| 669 | + } |
| 670 | + }; |
| 671 | + equalsRenderer = new LabelRenderer() { |
| 672 | + public void setValue(Object value, int row) { |
| 673 | + SkipNode node = (SkipNode) value; |
| 674 | + setText(Bundle.SkipNodeRenderer_Instances(NumberFormat.getInstance().format(node.skipped))); |
| 675 | + setMargin(3, 2, 3, 0); |
| 676 | + } |
| 677 | + |
| 678 | + public String toString() { |
| 679 | + return " " + getText() + " "; // NOI18N |
| 680 | + } |
| 681 | + }; |
| 682 | + classRenderer = new ClassNodeRenderer(heap); |
| 683 | + renderers = new ProfilerRenderer[]{nameRenderer, equalsRenderer, classRenderer}; |
| 684 | + } |
| 685 | + |
| 686 | + public Icon getIcon() { |
| 687 | + return nameRenderer.getIcon(); |
| 688 | + } |
| 689 | + |
| 690 | + public String getShortName() { |
| 691 | + return nameRenderer.toString(); |
| 692 | + } |
| 693 | + |
| 694 | + protected ProfilerRenderer[] valueRenderers() { |
| 695 | + return renderers; |
636 | 696 | }
|
637 | 697 |
|
638 |
| - private ObjectFieldValue getNextReference() { |
639 |
| - return reference; |
| 698 | + public void setValue(Object value, int row) { |
| 699 | + HeapViewerNode node = (HeapViewerNode) value; |
| 700 | + |
| 701 | + nameRenderer.setValue(node, row); |
| 702 | + equalsRenderer.setValue(node, row); |
| 703 | + classRenderer.setValue(new ClassNode(((SkipNode) node).getJavaClass()), row); |
640 | 704 | }
|
641 | 705 | }
|
642 |
| - |
| 706 | + |
| 707 | + @ServiceProvider(service = HeapViewerRenderer.Provider.class) |
| 708 | + public static class PathToGCRootRendererProvider extends HeapViewerRenderer.Provider { |
| 709 | + |
| 710 | + @Override |
| 711 | + public boolean supportsView(HeapContext context, String viewID) { |
| 712 | + return "java_objects_gcroots".equals(viewID); // NOI18N |
| 713 | + } |
| 714 | + |
| 715 | + @Override |
| 716 | + public void registerRenderers(Map<Class<? extends HeapViewerNode>, HeapViewerRenderer> renderers, HeapContext context) { |
| 717 | + renderers.put(SkipNode.class, new SkipNodeRenderer(context.getFragment().getHeap())); |
| 718 | + } |
| 719 | + |
| 720 | + } |
| 721 | + |
643 | 722 | @ServiceProvider(service=HeapViewPlugin.Provider.class, position = 400)
|
644 | 723 | public static class Provider extends HeapViewPlugin.Provider {
|
645 | 724 |
|
|
0 commit comments