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
25package sun.jvm.hotspot.ui.tree;
26
27import java.io.*;
28import sun.jvm.hotspot.oops.*;
29import sun.jvm.hotspot.debugger.*;
30import 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
38public 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}
281