diff agent/src/share/classes/sun/jvm/hotspot/ui/Inspector.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children c18cbe5936b8
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/ui/Inspector.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,358 @@
+/*
+ * Copyright 2000-2006 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.ui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.tree.TreePath;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.oops.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.ui.tree.*;
+import sun.jvm.hotspot.utilities.*;
+
+/** This class implements tree-browsing functionality of a particular
+    SimpleTreeNode, and is only designed to be used in a debugging
+    system. It uses a SimpleTreeModel internally. It can inspect both
+    oops as well as C++ objects described by the VMStructs database in
+    the target VM. */
+
+public class Inspector extends SAPanel {
+  private JTree tree;
+  private SimpleTreeModel model;
+
+  // UI widgets we need permanent handles to
+  private HistoryComboBox addressField;
+  private JLabel statusLabel;
+
+  private JButton            livenessButton;
+  private ActionListener     livenessButtonListener;
+  private ActionListener     showLivenessListener;
+  private static final String computeLivenessText = "Compute Liveness";
+  private static final String showLivenessText = "Show Liveness";
+  private JLabel liveStatus;
+  private LivenessPathList list = null;
+  private Oop currentOop = null;
+
+  public Inspector() {
+    model = new SimpleTreeModel();
+    tree = new JTree(model);
+
+    setLayout(new BorderLayout());
+    Box hbox = Box.createHorizontalBox();
+    JButton button = new JButton("Previous Oop");
+    button.addActionListener(new ActionListener() {
+        public void actionPerformed(ActionEvent e) {
+          String text = addressField.getText();
+          try {
+            VM vm = VM.getVM();
+            Address a = vm.getDebugger().parseAddress(text);
+            OopHandle handle = a.addOffsetToAsOopHandle(-vm.getAddressSize());
+            addressField.setText(handle.toString());
+          } catch (Exception ex) {
+          }
+        }
+      });
+    hbox.add(button);
+    hbox.add(new JLabel("Address / C++ Expression: "));
+    addressField = new HistoryComboBox();
+    hbox.add(addressField);
+    statusLabel = new JLabel();
+    hbox.add(statusLabel);
+
+    Box hboxDown = Box.createHorizontalBox();
+    hboxDown.add(Box.createGlue());
+
+    livenessButton = new JButton(computeLivenessText);
+    livenessButtonListener = new ActionListener() {
+          public void actionPerformed(ActionEvent e) {
+               if (currentOop != null) {
+                  fireComputeLiveness();
+               }
+               return;
+         }
+    };
+    showLivenessListener = new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+      fireShowLiveness();
+      }
+    };
+    livenessButton.addActionListener(livenessButtonListener);
+    hboxDown.add(livenessButton);
+    hboxDown.add(Box.createGlue());
+
+    liveStatus = new JLabel();
+    hboxDown.add(liveStatus);
+    hboxDown.add(Box.createGlue());
+
+    add(hbox, BorderLayout.NORTH);
+    add(hboxDown, BorderLayout.SOUTH);
+
+    addressField.addActionListener(new ActionListener() {
+        public void actionPerformed(ActionEvent e) {
+          String text = addressField.getText();
+          try {
+            Address a = VM.getVM().getDebugger().parseAddress(text);
+            int max_searches = 1000;
+            int searches = 0;
+            int offset = 0;
+            Oop oop = null;
+            if (a != null) {
+              OopHandle handle = a.addOffsetToAsOopHandle(0);
+              while (searches < max_searches) {
+                searches++;
+                if (RobustOopDeterminator.oopLooksValid(handle)) {
+                  try {
+                    oop = VM.getVM().getObjectHeap().newOop(handle);
+                    addressField.setText(handle.toString());
+                    break;
+                  } catch (UnknownOopException ex) {
+                    // ok
+                  } catch (RuntimeException ex) {
+                    ex.printStackTrace();
+                  }
+                }
+                offset -= 4;
+                handle = a.addOffsetToAsOopHandle(offset);
+              }
+            }
+            if (oop != currentOop) {
+              currentOop = oop;
+              liveStatus.setText("");
+              list = null;
+              if (livenessButton.getText().equals(showLivenessText)) {
+                livenessButton.setText(computeLivenessText);
+                livenessButton.removeActionListener(showLivenessListener);
+                livenessButton.addActionListener(livenessButtonListener);
+              }
+            }
+
+            if (oop != null) {
+              statusLabel.setText("");
+              setRoot(new OopTreeNodeAdapter(oop, null));
+              return;
+            }
+
+            // Try to treat this address as a C++ object and deduce its type
+            Type t = VM.getVM().getTypeDataBase().guessTypeForAddress(a);
+            if (t != null) {
+              statusLabel.setText("");
+              setRoot(new CTypeTreeNodeAdapter(a, t, null));
+              return;
+            }
+
+            statusLabel.setText("<bad oop or unknown C++ object " + text + ">");
+          }
+          catch (NumberFormatException ex) {
+              currentOop = null;
+              liveStatus.setText("");
+              list = null;
+              if (livenessButton.getText().equals(showLivenessText)) {
+                livenessButton.setText(computeLivenessText);
+                livenessButton.removeActionListener(showLivenessListener);
+                livenessButton.addActionListener(livenessButtonListener);
+              }
+            // Try to treat this as a C++ expression
+            CPPExpressions.CastExpr cast = CPPExpressions.parseCast(text);
+            if (cast != null) {
+              TypeDataBase db = VM.getVM().getTypeDataBase();
+              Type t = db.lookupType(cast.getType());
+              if (t == null) {
+                statusLabel.setText("<unknown C++ type \"" + cast.getType() + "\">");
+              } else {
+                try {
+                  Address a = VM.getVM().getDebugger().parseAddress(cast.getAddress());
+                  statusLabel.setText("");
+                  setRoot(new CTypeTreeNodeAdapter(a, t, null));
+                } catch (NumberFormatException ex2) {
+                  statusLabel.setText("<bad address " + cast.getAddress() + ">");
+                }
+              }
+              return;
+            }
+            CPPExpressions.StaticFieldExpr stat = CPPExpressions.parseStaticField(text);
+            if (stat != null) {
+              TypeDataBase db = VM.getVM().getTypeDataBase();
+              Type t = db.lookupType(stat.getContainingType());
+              if (t == null) {
+                statusLabel.setText("<unknown C++ type \"" + stat.getContainingType() + "\">");
+              } else {
+                sun.jvm.hotspot.types.Field f = t.getField(stat.getFieldName(), true, false);
+                if (f == null) {
+                  statusLabel.setText("<unknown field \"" + stat.getFieldName() + "\" in type \"" +
+                                      stat.getContainingType() + "\">");
+                } else if (!f.isStatic()) {
+                  statusLabel.setText("<field \"" + stat.getContainingType() + "::" +
+                                      stat.getFieldName() + "\" was not static>");
+                } else {
+                  Type fieldType = f.getType();
+                  if (fieldType.isPointerType()) {
+                    fieldType = ((PointerType) fieldType).getTargetType();
+
+                    // Try to get a more derived type
+                    Type typeGuess = db.guessTypeForAddress(f.getAddress());
+                    if (typeGuess != null) {
+                      fieldType = typeGuess;
+                    }
+
+                    statusLabel.setText("");
+                    setRoot(new CTypeTreeNodeAdapter(f.getAddress(),
+                                                     fieldType,
+                                                     new NamedFieldIdentifier(text)));
+                  } else {
+                    statusLabel.setText("");
+                    setRoot(new CTypeTreeNodeAdapter(f.getStaticFieldAddress(),
+                                                     f.getType(),
+                                                     new NamedFieldIdentifier(text)));
+                  }
+                }
+              }
+              return;
+            }
+
+            statusLabel.setText("<parse error>");
+          }
+          catch (AddressException ex) {
+            ex.printStackTrace();
+            currentOop = null;
+            liveStatus.setText("");
+            list = null;
+            if (livenessButton.getText().equals(showLivenessText)) {
+              livenessButton.setText(computeLivenessText);
+              livenessButton.removeActionListener(showLivenessListener);
+              livenessButton.addActionListener(livenessButtonListener);
+            }
+            statusLabel.setText("<bad address>");
+          }
+          catch (Exception ex) {
+            ex.printStackTrace();
+            currentOop = null;
+            liveStatus.setText("");
+            list = null;
+            if (livenessButton.getText().equals(showLivenessText)) {
+              livenessButton.setText(computeLivenessText);
+              livenessButton.removeActionListener(showLivenessListener);
+              livenessButton.addActionListener(livenessButtonListener);
+            }
+            statusLabel.setText("<error constructing oop>");
+          }
+        }
+      });
+
+    MouseListener ml = new MouseAdapter() {
+        public void mousePressed(MouseEvent e) {
+          int selRow = tree.getRowForLocation(e.getX(), e.getY());
+          TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
+          if(selRow != -1) {
+            if (e.getClickCount() == 1 && (e.getModifiersEx() & InputEvent.SHIFT_DOWN_MASK) != 0) {
+              Object node = tree.getLastSelectedPathComponent();
+              if (node != null && node instanceof SimpleTreeNode) {
+                showInspector((SimpleTreeNode)node);
+              }
+            }
+          }
+        }
+      };
+    tree.addMouseListener(ml);
+
+    JScrollPane scrollPane = new JScrollPane(tree);
+
+    // Let's see what happens if we let the parent deal with resizing the panel
+    add(scrollPane, BorderLayout.CENTER);
+  }
+
+  public Inspector(final SimpleTreeNode root) {
+    this();
+    SwingUtilities.invokeLater( new Runnable() {
+        public void run() {
+          if (root instanceof OopTreeNodeAdapter) {
+            final Oop oop = ((OopTreeNodeAdapter)root).getOop();
+            addressField.setText(oop.getHandle().toString());
+          }
+          setRoot(root);
+        }
+      });
+  }
+
+  private void setRoot(SimpleTreeNode root) {
+    model.setRoot(root);
+
+    //    tree.invalidate();
+    //    tree.validate();
+    //    repaint();
+    // FIXME: invalidate? How to get to redraw? Will I have to make
+    // tree listeners work?
+  }
+
+  private void fireComputeLiveness() {
+    final Runnable cutoverButtonRunnable = new Runnable() {
+        public void run() {
+          list = LivenessAnalysis.computeAllLivenessPaths(currentOop);
+          if (list == null) {
+            liveStatus.setText("Oop is Dead");
+          } else {
+            liveStatus.setText("Oop is Alive");
+            livenessButton.removeActionListener(livenessButtonListener);
+            livenessButton.addActionListener(showLivenessListener);
+
+            livenessButton.setEnabled(true);
+            livenessButton.setText(showLivenessText);
+          }
+        }
+      };
+
+
+    if (VM.getVM().getRevPtrs() != null) {
+      cutoverButtonRunnable.run();
+    } else {
+      final WorkerThread worker = new WorkerThread();
+      worker.invokeLater(new Runnable() {
+          public void run() {
+            try {
+              ReversePtrsAnalysis rev = new ReversePtrsAnalysis();
+              rev.run();
+              cutoverButtonRunnable.run();
+            } finally {
+              worker.shutdown();
+            }
+          }
+        });
+    }
+  }
+
+  private void fireShowLiveness() {
+    if (list == null) {
+      return; // dead object
+    }
+
+    for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
+      SAListener listener = (SAListener) iter.next();
+      listener.showLiveness(currentOop, list);
+    }
+  }
+}