blob: b116e26417bf491d11ac6cf904d372c21ed6f91e [file] [log] [blame]
/*
* Copyright (c) 2000, 2006, 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 sun.jvm.hotspot.ui;
import java.io.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.oops.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.utilities.*;
import sun.jvm.hotspot.ui.table.*;
import sun.jvm.hotspot.ui.tree.*;
/** Lists objects along with their types */
public class ObjectListPanel extends SAPanel {
private ObjectListTableModel dataModel;
private JTable table;
private java.util.List elements;
private HeapProgressThunk thunk;
private boolean checkedForArrays;
private boolean hasArrays;
private int numColumns;
// For changing the text of the "Compute Liveness" button
private JButton livenessButton;
private ActionListener livenessButtonListener;
private static final String showLivenessText = "Show Liveness";
/** Takes a List<Oop> in constructor, and an optional
HeapProgressThunk used if computing liveness */
public ObjectListPanel(java.util.List els,
HeapProgressThunk thunk) {
super();
elements = els;
this.thunk = thunk;
computeNumColumns();
setLayout(new BorderLayout());
dataModel = new ObjectListTableModel();
table = new JTable(dataModel);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
JTableHeader header = table.getTableHeader();
header.setDefaultRenderer(new SortHeaderCellRenderer(header, dataModel));
header.addMouseListener(new SortHeaderMouseAdapter(table, dataModel));
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane, BorderLayout.CENTER);
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
Box box = Box.createHorizontalBox();
box.add(Box.createGlue());
JButton button = new JButton("Inspect");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireShowInspector();
}
});
box.add(button);
box.add(Box.createHorizontalStrut(20));
// Liveness button
button = new JButton();
livenessButton = button;
if (VM.getVM().getRevPtrs() == null) {
button.setText("Compute Liveness");
livenessButtonListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireComputeLiveness();
}
};
} else {
button.setText("Show Liveness Path");
livenessButtonListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireShowLiveness();
}
};
}
button.addActionListener(livenessButtonListener);
box.add(button);
box.add(Box.createGlue());
panel.add(box);
add(panel, BorderLayout.SOUTH);
}
//--------------------------------------------------------------------------------
// Internals only below this point
//
private static class AddressWrapper implements Comparable {
private Address address;
private AddressWrapper(Address address) {
this.address = address;
}
public String toString() {
return address.toString();
}
public int compareTo(Object o) {
AddressWrapper wrapper = (AddressWrapper) o;
Address addr = wrapper.address;
if (AddressOps.lessThan(address, addr)) return -1;
if (AddressOps.greaterThan(address, addr)) return 1;
return 0;
}
}
private class ObjectListTableModel extends SortableTableModel {
public ObjectListTableModel() {
// Set the rows
this.elements = ObjectListPanel.this.elements;
setComparator(new ObjectListComparator(this));
}
public int getColumnCount() { return numColumns; }
public int getRowCount() { return elements.size(); }
public String getColumnName(int col) {
switch (col) {
case 0:
return "Address";
case 1:
return "Oop";
case 2:
if (hasArrays) {
return "Length";
} else {
return "Class Description";
}
case 3:
if (hasArrays) {
return "Class Description";
} else if (VM.getVM().getRevPtrs() != null) {
return "Liveness";
}
case 4:
if (hasArrays && (VM.getVM().getRevPtrs() != null)) {
return "Liveness";
}
}
throw new RuntimeException("Index " + col + " out of bounds");
}
public Object getValueAt(int row, int col) {
Oop oop = (Oop) elements.get(row);
return getValueForColumn(oop, col);
}
public Object getValueForColumn(Oop oop, int col) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
switch (col) {
case 0:
return new AddressWrapper(oop.getHandle());
case 1:
oop.printValueOn(new PrintStream(bos));
break;
case 2:
if (hasArrays) {
if (oop instanceof Array) {
return new Long(((Array) oop).getLength());
}
return null;
} else {
oop.getKlass().printValueOn(new PrintStream(bos));
break;
}
case 3:
if (hasArrays) {
oop.getKlass().printValueOn(new PrintStream(bos));
break;
} else {
if (VM.getVM().getRevPtrs() != null) {
if (VM.getVM().getRevPtrs().get(oop) != null) {
return "Alive";
} else {
return "Dead";
}
}
}
case 4:
if (hasArrays) {
if (VM.getVM().getRevPtrs() != null) {
if (VM.getVM().getRevPtrs().get(oop) != null) {
return "Alive";
} else {
return "Dead";
}
}
}
default:
throw new RuntimeException("Column " + col + " out of bounds");
}
return bos.toString();
}
private class ObjectListComparator extends TableModelComparator {
public ObjectListComparator(ObjectListTableModel model) {
super(model);
}
/**
* Returns the value for the comparing object for the
* column.
*
* @param obj Object that was passed for Comparator
* @param column the column to retrieve
*/
public Object getValueForColumn(Object obj, int column) {
ObjectListTableModel omodel = (ObjectListTableModel)model;
return omodel.getValueForColumn((Oop) obj, column);
}
}
}
private void fireShowInspector() {
int i = table.getSelectedRow();
if (i < 0) {
return;
}
Oop oop = (Oop) elements.get(i);
for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
SAListener listener = (SAListener) iter.next();
listener.showInspector(new OopTreeNodeAdapter(oop, null));
}
}
private void fireComputeLiveness() {
final Runnable cutoverButtonRunnable = new Runnable() {
public void run() {
livenessButton.removeActionListener(livenessButtonListener);
livenessButtonListener = null;
livenessButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireShowLiveness();
}
});
computeNumColumns();
livenessButton.setEnabled(true);
livenessButton.setText(showLivenessText);
dataModel.fireTableStructureChanged();
}
};
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();
if (thunk != null) {
rev.setHeapProgressThunk(thunk);
}
rev.run();
cutoverButtonRunnable.run();
} finally {
worker.shutdown();
}
}
});
}
}
private void fireShowLiveness() {
if (VM.getVM().getRevPtrs() == null) {
return;
}
int i = table.getSelectedRow();
if (i < 0) {
return;
}
Oop oop = (Oop) elements.get(i);
LivenessPathList list = LivenessAnalysis.computeAllLivenessPaths(oop);
if (list == null) {
return; // dead object
}
for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
SAListener listener = (SAListener) iter.next();
listener.showLiveness(oop, list);
}
}
private void checkForArrays() {
if (checkedForArrays) return;
checkedForArrays = true;
for (Iterator iter = elements.iterator(); iter.hasNext(); ) {
if (iter.next() instanceof Array) {
hasArrays = true;
return;
}
}
}
private void computeNumColumns() {
checkForArrays();
numColumns = 3;
if (hasArrays) ++numColumns;
if (VM.getVM().getRevPtrs() != null) ++numColumns;
}
}