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