View Javadoc
1   /*
2    * Copyright (c) 2000, 2012, 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.tree;
26  
27  import java.io.*;
28  import sun.jvm.hotspot.oops.*;
29  import sun.jvm.hotspot.debugger.*;
30  import sun.jvm.hotspot.runtime.*;
31  
32  /** An adapter class which allows oops to be displayed in a tree via
33      the SimpleTreeNode interface. FIXME: must attach this to some sort
34      of policy object which determines how to display names and whether
35      VM fields should be shown. (Must also fix oop visitation mechanism
36      in oops package.) */
37  
38  public class OopTreeNodeAdapter extends FieldTreeNodeAdapter {
39    private Oop oop;
40  
41    /** The oop may be null (for oop fields of oops which are null); the
42        FieldIdentifier may also be null (for the root node).
43        treeTableMode defaults to false. */
44    public OopTreeNodeAdapter(Oop oop, FieldIdentifier id) {
45      this(oop, id, false);
46    }
47  
48    /** The oop may be null (for oop fields of oops which are null); the
49        FieldIdentifier may also be null (for the root node). */
50    public OopTreeNodeAdapter(Oop oop, FieldIdentifier id, boolean treeTableMode) {
51      super(id, treeTableMode);
52      this.oop = oop;
53    }
54  
55    public Oop getOop() {
56      return oop;
57    }
58  
59    public int getChildCount() {
60      if (oop == null) {
61        return 0;
62      }
63  
64      Counter c = new Counter();
65      oop.iterate(c, true);
66      return c.getNumFields() + (VM.getVM().getRevPtrs() == null ? 0 : 1);
67    }
68  
69    public SimpleTreeNode getChild(int index) {
70      if (oop == null) {
71        return null;
72      }
73      if (VM.getVM().getRevPtrs() != null) {
74        if (index == 0) {
75          return new RevPtrsTreeNodeAdapter(oop, getTreeTableMode());
76        } else {
77          index -= 1;
78        }
79      }
80  
81      Fetcher f = new Fetcher(index);
82      oop.iterate(f, true);
83      return f.getChild();
84    }
85  
86    public boolean isLeaf() {
87      return (oop == null);
88    }
89  
90    public int getIndexOfChild(SimpleTreeNode child) {
91      if (child instanceof RevPtrsTreeNodeAdapter) {
92        // assert(VM.getVM().getRevPtrs() != null, "Only created from revptrs");
93        return 0;
94      }
95      FieldIdentifier id = ((FieldTreeNodeAdapter) child).getID();
96      Finder f = new Finder(id);
97      oop.iterate(f, true);
98      return f.getIndex() + (VM.getVM().getRevPtrs() == null ? 0 : 1);
99    }
100 
101   public String getValue() {
102     if (oop != null) {
103       // FIXME: choose style of printing depending on whether we're
104       // displaying VM fields? Want to make Java objects look like
105       // Java objects.
106       ByteArrayOutputStream bos = new ByteArrayOutputStream();
107       Oop.printOopValueOn(oop, new PrintStream(bos));
108       return bos.toString();
109     }
110     return "null";
111   }
112 
113   /** Should be applied to one oop at a time, then have the number of
114       fields fetched. FIXME: want this to distinguish between VM and
115       non-VM fields. */
116   static class Counter extends DefaultOopVisitor {
117     private int numFields;
118 
119     public int getNumFields() {
120       return numFields;
121     }
122 
123     public void prologue() {
124       numFields = 0;
125     }
126 
127     public void doMetadata(MetadataField field, boolean isVMField) { ++numFields; }
128     public void doOop(OopField field, boolean isVMField)         { ++numFields; }
129     public void doByte(ByteField field, boolean isVMField)       { ++numFields; }
130     public void doChar(CharField field, boolean isVMField)       { ++numFields; }
131     public void doBoolean(BooleanField field, boolean isVMField) { ++numFields; }
132     public void doShort(ShortField field, boolean isVMField)     { ++numFields; }
133     public void doInt(IntField field, boolean isVMField)         { ++numFields; }
134     public void doLong(LongField field, boolean isVMField)       { ++numFields; }
135     public void doFloat(FloatField field, boolean isVMField)     { ++numFields; }
136     public void doDouble(DoubleField field, boolean isVMField)   { ++numFields; }
137     public void doCInt(CIntField field, boolean isVMField)       { ++numFields; }
138   }
139 
140   /** Creates a new SimpleTreeNode for the given field. FIXME: want
141       this to distinguish between VM and non-VM fields. */
142   class Fetcher extends DefaultOopVisitor {
143     private int index;
144     private int curField;
145     private SimpleTreeNode child;
146 
147     public Fetcher(int index) {
148       this.index = index;
149     }
150 
151     public SimpleTreeNode getChild() {
152       return child;
153     }
154 
155     public void prologue() {
156       curField = 0;
157     }
158 
159     public void doMetadata(MetadataField field, boolean isVMField) {
160       if (curField == index) {
161         try {
162           child = new MetadataTreeNodeAdapter(field.getValue(getObj()), field.getID(), getTreeTableMode());
163         } catch (AddressException e) {
164           child = new BadAddressTreeNodeAdapter(getObj().getHandle().getAddressAt(field.getOffset()), field, getTreeTableMode());
165         } catch (UnknownOopException e) {
166           child = new BadAddressTreeNodeAdapter(getObj().getHandle().getAddressAt(field.getOffset()), field, getTreeTableMode());
167         }
168       }
169       ++curField;
170     }
171 
172     public void doOop(OopField field, boolean isVMField) {
173       if (curField == index) {
174         try {
175           child = new OopTreeNodeAdapter(field.getValue(getObj()), field.getID(), getTreeTableMode());
176         } catch (AddressException e) {
177           child = new BadAddressTreeNodeAdapter(field.getValueAsOopHandle(getObj()), field, getTreeTableMode());
178         } catch (UnknownOopException e) {
179           child = new BadAddressTreeNodeAdapter(field.getValueAsOopHandle(getObj()), field, getTreeTableMode());
180         }
181       }
182       ++curField;
183     }
184 
185     public void doByte(ByteField field, boolean isVMField) {
186       if (curField == index) {
187         child = new LongTreeNodeAdapter(field.getValue(getObj()) & 0xFF, field.getID(), getTreeTableMode());
188       }
189       ++curField;
190     }
191 
192     public void doChar(CharField field, boolean isVMField) {
193       if (curField == index) {
194         child = new CharTreeNodeAdapter(field.getValue(getObj()), field.getID(), getTreeTableMode());
195       }
196       ++curField;
197     }
198 
199     public void doBoolean(BooleanField field, boolean isVMField) {
200       if (curField == index) {
201         child = new BooleanTreeNodeAdapter(field.getValue(getObj()), field.getID(), getTreeTableMode());
202       }
203       ++curField;
204     }
205 
206     public void doShort(ShortField field, boolean isVMField) {
207       if (curField == index) {
208         child = new LongTreeNodeAdapter(field.getValue(getObj()) & 0xFFFF, field.getID(), getTreeTableMode());
209       }
210       ++curField;
211     }
212 
213     public void doInt(IntField field, boolean isVMField) {
214       if (curField == index) {
215         child = new LongTreeNodeAdapter(field.getValue(getObj()) & 0xFFFFFFFF, field.getID(), getTreeTableMode());
216       }
217       ++curField;
218     }
219 
220     public void doLong(LongField field, boolean isVMField) {
221       if (curField == index) {
222         child = new LongTreeNodeAdapter(field.getValue(getObj()), field.getID(), getTreeTableMode());
223       }
224       ++curField;
225     }
226 
227     public void doFloat(FloatField field, boolean isVMField) {
228       if (curField == index) {
229         child = new FloatTreeNodeAdapter(field.getValue(getObj()), field.getID(), getTreeTableMode());
230       }
231       ++curField;
232     }
233 
234     public void doDouble(DoubleField field, boolean isVMField) {
235       if (curField == index) {
236         child = new DoubleTreeNodeAdapter(field.getValue(getObj()), field.getID(), getTreeTableMode());
237       }
238       ++curField;
239     }
240 
241     public void doCInt(CIntField field, boolean isVMField) {
242       if (curField == index) {
243         child = new LongTreeNodeAdapter(field.getValue(getObj()), field.getID(), getTreeTableMode());
244       }
245       ++curField;
246     }
247   }
248 
249   /** Finds the index of the given FieldIdentifier. */
250   static class Finder extends DefaultOopVisitor {
251     private FieldIdentifier id;
252     private int curField;
253     private int index;
254 
255     public Finder(FieldIdentifier id) {
256       this.id = id;
257     }
258 
259     /** Returns -1 if not found */
260     public int getIndex() {
261       return index;
262     }
263 
264     public void prologue() {
265       curField = 0;
266       index = -1;
267     }
268 
269     public void doOop(OopField field, boolean isVMField)         { if (field.getID().equals(id)) { index = curField; } ++curField; }
270     public void doByte(ByteField field, boolean isVMField)       { if (field.getID().equals(id)) { index = curField; } ++curField; }
271     public void doChar(CharField field, boolean isVMField)       { if (field.getID().equals(id)) { index = curField; } ++curField; }
272     public void doBoolean(BooleanField field, boolean isVMField) { if (field.getID().equals(id)) { index = curField; } ++curField; }
273     public void doShort(ShortField field, boolean isVMField)     { if (field.getID().equals(id)) { index = curField; } ++curField; }
274     public void doInt(IntField field, boolean isVMField)         { if (field.getID().equals(id)) { index = curField; } ++curField; }
275     public void doLong(LongField field, boolean isVMField)       { if (field.getID().equals(id)) { index = curField; } ++curField; }
276     public void doFloat(FloatField field, boolean isVMField)     { if (field.getID().equals(id)) { index = curField; } ++curField; }
277     public void doDouble(DoubleField field, boolean isVMField)   { if (field.getID().equals(id)) { index = curField; } ++curField; }
278     public void doCInt(CIntField field, boolean isVMField)       { if (field.getID().equals(id)) { index = curField; } ++curField; }
279   }
280 }