Mercurial > hg > truffle
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); + } + } +}