View Javadoc
1   /*
2    * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.
8    *
9    * This code is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12   * version 2 for more details (a copy is included in the LICENSE file that
13   * accompanied this code).
14   *
15   * You should have received a copy of the GNU General Public License version
16   * 2 along with this work; if not, write to the Free Software Foundation,
17   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18   *
19   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20   * or visit www.oracle.com if you need additional information or have any
21   * questions.
22   *
23   */
24  
25  package sun.jvm.hotspot.ui;
26  
27  import java.io.*;
28  import java.util.*;
29  import java.awt.*;
30  import java.awt.event.*;
31  import javax.swing.*;
32  import javax.swing.table.*;
33  
34  import sun.jvm.hotspot.debugger.*;
35  import sun.jvm.hotspot.oops.*;
36  import sun.jvm.hotspot.runtime.*;
37  import sun.jvm.hotspot.utilities.*;
38  import sun.jvm.hotspot.ui.table.*;
39  import sun.jvm.hotspot.ui.tree.*;
40  
41  /** Lists objects along with their types */
42  
43  public class ObjectListPanel extends SAPanel {
44    private ObjectListTableModel dataModel;
45    private JTable             table;
46    private java.util.List     elements;
47    private HeapProgressThunk  thunk;
48    private boolean            checkedForArrays;
49    private boolean            hasArrays;
50    private int                numColumns;
51    // For changing the text of the "Compute Liveness" button
52    private JButton            livenessButton;
53    private ActionListener     livenessButtonListener;
54    private static final String showLivenessText = "Show Liveness";
55  
56    /** Takes a List<Oop> in constructor, and an optional
57        HeapProgressThunk used if computing liveness */
58    public ObjectListPanel(java.util.List els,
59                           HeapProgressThunk thunk) {
60      super();
61  
62      elements = els;
63      this.thunk = thunk;
64      computeNumColumns();
65  
66      setLayout(new BorderLayout());
67  
68      dataModel = new ObjectListTableModel();
69  
70      table = new JTable(dataModel);
71      table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
72      JTableHeader header = table.getTableHeader();
73      header.setDefaultRenderer(new SortHeaderCellRenderer(header, dataModel));
74      header.addMouseListener(new SortHeaderMouseAdapter(table, dataModel));
75  
76      JScrollPane scrollPane = new JScrollPane(table);
77      add(scrollPane, BorderLayout.CENTER);
78  
79      JPanel panel = new JPanel();
80      panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
81      panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
82      Box box = Box.createHorizontalBox();
83      box.add(Box.createGlue());
84      JButton button = new JButton("Inspect");
85      button.addActionListener(new ActionListener() {
86          public void actionPerformed(ActionEvent e) {
87            fireShowInspector();
88          }
89        });
90      box.add(button);
91  
92      box.add(Box.createHorizontalStrut(20));
93  
94      // Liveness button
95      button = new JButton();
96      livenessButton = button;
97      if (VM.getVM().getRevPtrs() == null) {
98        button.setText("Compute Liveness");
99        livenessButtonListener = new ActionListener() {
100           public void actionPerformed(ActionEvent e) {
101             fireComputeLiveness();
102           }
103         };
104     } else {
105       button.setText("Show Liveness Path");
106       livenessButtonListener = new ActionListener() {
107           public void actionPerformed(ActionEvent e) {
108             fireShowLiveness();
109           }
110         };
111     }
112     button.addActionListener(livenessButtonListener);
113     box.add(button);
114     box.add(Box.createGlue());
115     panel.add(box);
116     add(panel, BorderLayout.SOUTH);
117   }
118 
119   //--------------------------------------------------------------------------------
120   // Internals only below this point
121   //
122 
123   private static class AddressWrapper implements Comparable {
124     private Address address;
125 
126     private AddressWrapper(Address address) {
127       this.address = address;
128     }
129 
130     public String toString() {
131       return address.toString();
132     }
133 
134     public int compareTo(Object o) {
135       AddressWrapper wrapper = (AddressWrapper) o;
136       Address addr = wrapper.address;
137       if (AddressOps.lessThan(address, addr)) return -1;
138       if (AddressOps.greaterThan(address, addr)) return 1;
139       return 0;
140     }
141   }
142 
143   private class ObjectListTableModel extends SortableTableModel {
144     public ObjectListTableModel() {
145       // Set the rows
146       this.elements = ObjectListPanel.this.elements;
147       setComparator(new ObjectListComparator(this));
148     }
149 
150     public int getColumnCount() { return numColumns;      }
151     public int getRowCount()    { return elements.size(); }
152     public String getColumnName(int col) {
153       switch (col) {
154       case 0:
155         return "Address";
156       case 1:
157         return "Oop";
158       case 2:
159         if (hasArrays) {
160           return "Length";
161         } else {
162           return "Class Description";
163         }
164       case 3:
165         if (hasArrays) {
166           return "Class Description";
167         } else if (VM.getVM().getRevPtrs() != null) {
168           return "Liveness";
169         }
170       case 4:
171         if (hasArrays && (VM.getVM().getRevPtrs() != null)) {
172           return "Liveness";
173         }
174       }
175       throw new RuntimeException("Index " + col + " out of bounds");
176     }
177 
178     public Object getValueAt(int row, int col) {
179       Oop oop = (Oop) elements.get(row);
180       return getValueForColumn(oop, col);
181     }
182 
183     public Object getValueForColumn(Oop oop, int col) {
184       ByteArrayOutputStream bos = new ByteArrayOutputStream();
185 
186       switch (col) {
187       case 0:
188         return new AddressWrapper(oop.getHandle());
189       case 1:
190         oop.printValueOn(new PrintStream(bos));
191         break;
192       case 2:
193         if (hasArrays) {
194           if (oop instanceof Array) {
195             return new Long(((Array) oop).getLength());
196           }
197           return null;
198         } else {
199           oop.getKlass().printValueOn(new PrintStream(bos));
200           break;
201         }
202       case 3:
203         if (hasArrays) {
204           oop.getKlass().printValueOn(new PrintStream(bos));
205           break;
206         } else {
207           if (VM.getVM().getRevPtrs() != null) {
208             if (VM.getVM().getRevPtrs().get(oop) != null) {
209               return "Alive";
210             } else {
211               return "Dead";
212             }
213           }
214         }
215       case 4:
216         if (hasArrays) {
217           if (VM.getVM().getRevPtrs() != null) {
218             if (VM.getVM().getRevPtrs().get(oop) != null) {
219               return "Alive";
220             } else {
221               return "Dead";
222             }
223           }
224         }
225       default:
226         throw new RuntimeException("Column " + col + " out of bounds");
227       }
228 
229       return bos.toString();
230     }
231 
232     private class ObjectListComparator extends TableModelComparator {
233       public ObjectListComparator(ObjectListTableModel model) {
234         super(model);
235       }
236 
237       /**
238        * Returns the value for the comparing object for the
239        * column.
240        *
241        * @param obj Object that was passed for Comparator
242        * @param column the column to retrieve
243        */
244       public Object getValueForColumn(Object obj, int column) {
245         ObjectListTableModel omodel = (ObjectListTableModel)model;
246         return omodel.getValueForColumn((Oop) obj, column);
247       }
248     }
249   }
250 
251   private void fireShowInspector() {
252     int i = table.getSelectedRow();
253     if (i < 0) {
254       return;
255     }
256 
257     Oop oop = (Oop) elements.get(i);
258 
259     for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
260       SAListener listener = (SAListener) iter.next();
261       listener.showInspector(new OopTreeNodeAdapter(oop, null));
262     }
263   }
264 
265   private void fireComputeLiveness() {
266     final Runnable cutoverButtonRunnable = new Runnable() {
267         public void run() {
268           livenessButton.removeActionListener(livenessButtonListener);
269           livenessButtonListener = null;
270           livenessButton.addActionListener(new ActionListener() {
271               public void actionPerformed(ActionEvent e) {
272                 fireShowLiveness();
273               }
274             });
275           computeNumColumns();
276           livenessButton.setEnabled(true);
277           livenessButton.setText(showLivenessText);
278           dataModel.fireTableStructureChanged();
279         }
280       };
281 
282 
283     if (VM.getVM().getRevPtrs() != null) {
284       cutoverButtonRunnable.run();
285     } else {
286       final WorkerThread worker = new WorkerThread();
287       worker.invokeLater(new Runnable() {
288           public void run() {
289             try {
290               ReversePtrsAnalysis rev = new ReversePtrsAnalysis();
291               if (thunk != null) {
292                 rev.setHeapProgressThunk(thunk);
293               }
294               rev.run();
295               cutoverButtonRunnable.run();
296             } finally {
297               worker.shutdown();
298             }
299           }
300         });
301     }
302   }
303 
304   private void fireShowLiveness() {
305     if (VM.getVM().getRevPtrs() == null) {
306       return;
307     }
308 
309     int i = table.getSelectedRow();
310     if (i < 0) {
311       return;
312     }
313 
314     Oop oop = (Oop) elements.get(i);
315     LivenessPathList list = LivenessAnalysis.computeAllLivenessPaths(oop);
316     if (list == null) {
317       return; // dead object
318     }
319 
320     for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
321       SAListener listener = (SAListener) iter.next();
322       listener.showLiveness(oop, list);
323     }
324   }
325 
326   private void checkForArrays() {
327     if (checkedForArrays) return;
328     checkedForArrays = true;
329     for (Iterator iter = elements.iterator(); iter.hasNext(); ) {
330       if (iter.next() instanceof Array) {
331         hasArrays = true;
332         return;
333       }
334     }
335   }
336 
337   private void computeNumColumns() {
338     checkForArrays();
339     numColumns = 3;
340     if (hasArrays)        ++numColumns;
341     if (VM.getVM().getRevPtrs() != null)  ++numColumns;
342   }
343 }