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