1 /* 2 * Copyright 2004-2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 20 * CA 95054 USA or visit www.sun.com if you need additional information or 21 * have any questions. 22 * 23 */ 24 25 package sun.jvm.hotspot.utilities; 26 27 import java.io.*; 28 import sun.jvm.hotspot.debugger.*; 29 import sun.jvm.hotspot.memory.*; 30 import sun.jvm.hotspot.oops.*; 31 import sun.jvm.hotspot.runtime.*; 32 33 /** 34 * This is abstract base class for heap graph writers. This class does 35 * not assume any file format for the heap graph. It hides heap 36 * iteration, object (fields) iteration mechanism from derived 37 * classes. This class does not even accept OutputStream etc. so that 38 * derived class can construct specific writer/filter from input 39 * stream. 40 */ 41 42 public abstract class AbstractHeapGraphWriter implements HeapGraphWriter { 43 // the function iterates heap and calls Oop type specific writers 44 protected void write() throws IOException { 45 SymbolTable symTbl = VM.getVM().getSymbolTable(); 46 javaLangClass = symTbl.probe("java/lang/Class"); 47 javaLangString = symTbl.probe("java/lang/String"); 48 javaLangThread = symTbl.probe("java/lang/Thread"); 49 ObjectHeap heap = VM.getVM().getObjectHeap(); 50 try { 51 heap.iterate(new DefaultHeapVisitor() { 52 public void prologue(long usedSize) { 53 try { 54 writeHeapHeader(); 55 } catch (IOException exp) { 56 throw new RuntimeException(exp); 57 } 58 } 59 60 public boolean doObj(Oop oop) { 61 try { 62 if (oop instanceof TypeArray) { 63 writePrimitiveArray((TypeArray)oop); 64 } else if (oop instanceof ObjArray) { 65 Klass klass = oop.getKlass(); 66 ObjArrayKlass oak = (ObjArrayKlass) klass; 67 Klass bottomType = oak.getBottomKlass(); 68 if (bottomType instanceof InstanceKlass || 69 bottomType instanceof TypeArrayKlass) { 70 writeObjectArray((ObjArray)oop); 71 } else { 72 writeInternalObject(oop); 73 } 74 } else if (oop instanceof Instance) { 75 Instance instance = (Instance) oop; 76 Klass klass = instance.getKlass(); 77 Symbol name = klass.getName(); 78 if (name.equals(javaLangString)) { 79 writeString(instance); 80 } else if (name.equals(javaLangClass)) { 81 writeClass(instance); 82 } else if (name.equals(javaLangThread)) { 83 writeThread(instance); 84 } else { 85 klass = klass.getSuper(); 86 while (klass != null) { 87 name = klass.getName(); 88 if (name.equals(javaLangThread)) { 89 writeThread(instance); 90 return false; 91 } 92 klass = klass.getSuper(); 93 } 94 writeInstance(instance); 95 } 96 } else { 97 // not-a-Java-visible oop 98 writeInternalObject(oop); 99 } 100 } catch (IOException exp) { 101 throw new RuntimeException(exp); 102 } 103 return false; 104 } 105 106 public void epilogue() { 107 try { 108 writeHeapFooter(); 109 } catch (IOException exp) { 110 throw new RuntimeException(exp); 111 } 112 } 113 }); 114 115 // write JavaThreads 116 writeJavaThreads(); 117 118 // write JNI global handles 119 writeGlobalJNIHandles(); 120 121 } catch (RuntimeException re) { 122 handleRuntimeException(re); 123 } 124 } 125 126 protected void writeJavaThreads() throws IOException { 127 Threads threads = VM.getVM().getThreads(); 128 JavaThread jt = threads.first(); 129 int index = 1; 130 while (jt != null) { 131 if (jt.getThreadObj() != null) { 132 // Note that the thread serial number range is 1-to-N 133 writeJavaThread(jt, index); 134 index++; 135 } 136 jt = jt.next(); 137 } 138 } 139 140 protected void writeJavaThread(JavaThread jt, int index) 141 throws IOException { 142 } 143 144 protected void writeGlobalJNIHandles() throws IOException { 145 JNIHandles handles = VM.getVM().getJNIHandles(); 146 JNIHandleBlock blk = handles.globalHandles(); 147 if (blk != null) { 148 try { 149 blk.oopsDo(new AddressVisitor() { 150 public void visitAddress(Address handleAddr) { 151 try { 152 if (handleAddr != null) { 153 writeGlobalJNIHandle(handleAddr); 154 } 155 } catch (IOException exp) { 156 throw new RuntimeException(exp); 157 } 158 } 159 public void visitCompOopAddress(Address handleAddr) { 160 throw new RuntimeException("Should not reach here. JNIHandles are not compressed"); 161 } 162 }); 163 } catch (RuntimeException re) { 164 handleRuntimeException(re); 165 } 166 } 167 } 168 169 protected void writeGlobalJNIHandle(Address handleAddr) throws IOException { 170 } 171 172 protected void writeHeapHeader() throws IOException { 173 } 174 175 // write non-Java-visible (hotspot internal) object 176 protected void writeInternalObject(Oop oop) throws IOException { 177 } 178 179 // write Java primitive array 180 protected void writePrimitiveArray(TypeArray array) throws IOException { 181 writeObject(array); 182 } 183 184 // write Java object array 185 protected void writeObjectArray(ObjArray array) throws IOException { 186 writeObject(array); 187 } 188 189 protected void writeInstance(Instance instance) throws IOException { 190 writeObject(instance); 191 } 192 193 protected void writeString(Instance instance) throws IOException { 194 writeInstance(instance); 195 } 196 197 protected void writeClass(Instance instance) throws IOException { 198 writeInstance(instance); 199 } 200 201 protected void writeThread(Instance instance) throws IOException { 202 writeInstance(instance); 203 } 204 205 protected void writeObject(Oop oop) throws IOException { 206 writeObjectHeader(oop); 207 writeObjectFields(oop); 208 writeObjectFooter(oop); 209 } 210 211 protected void writeObjectHeader(Oop oop) throws IOException { 212 } 213 214 // write instance fields of given object 215 protected void writeObjectFields(final Oop oop) throws IOException { 216 try { 217 oop.iterate(new DefaultOopVisitor() { 218 public void doOop(OopField field, boolean isVMField) { 219 try { 220 Oop ref = field.getValue(oop); 221 if (ref instanceof TypeArray || 222 ref instanceof ObjArray || 223 ref instanceof Instance) { 224 writeReferenceField(oop, field); 225 } else { 226 writeInternalReferenceField(oop, field); 227 } 228 } catch (IOException exp) { 229 throw new RuntimeException(exp); 230 } 231 } 232 233 public void doByte(ByteField field, boolean isVMField) { 234 try { 235 writeByteField(oop, field); 236 } catch (IOException exp) { 237 throw new RuntimeException(exp); 238 } 239 } 240 241 public void doChar(CharField field, boolean isVMField) { 242 try { 243 writeCharField(oop, field); 244 } catch (IOException exp) { 245 throw new RuntimeException(exp); 246 } 247 } 248 249 public void doBoolean(BooleanField field, boolean vField) { 250 try { 251 writeBooleanField(oop, field); 252 } catch (IOException exp) { 253 throw new RuntimeException(exp); 254 } 255 } 256 257 public void doShort(ShortField field, boolean isVMField) { 258 try { 259 writeShortField(oop, field); 260 } catch (IOException exp) { 261 throw new RuntimeException(exp); 262 } 263 } 264 265 public void doInt(IntField field, boolean isVMField) { 266 try { 267 writeIntField(oop, field); 268 } catch (IOException exp) { 269 throw new RuntimeException(exp); 270 } 271 } 272 273 public void doLong(LongField field, boolean isVMField) { 274 try { 275 writeLongField(oop, field); 276 } catch (IOException exp) { 277 throw new RuntimeException(exp); 278 } 279 } 280 281 public void doFloat(FloatField field, boolean isVMField) { 282 try { 283 writeFloatField(oop, field); 284 } catch (IOException exp) { 285 throw new RuntimeException(exp); 286 } 287 } 288 289 public void doDouble(DoubleField field, boolean vField) { 290 try { 291 writeDoubleField(oop, field); 292 } catch (IOException exp) { 293 throw new RuntimeException(exp); 294 } 295 } 296 }, false); 297 } catch (RuntimeException re) { 298 handleRuntimeException(re); 299 } 300 } 301 302 // object field writers 303 protected void writeInternalReferenceField(Oop oop, OopField field) 304 throws IOException { 305 } 306 307 protected void writeReferenceField(Oop oop, OopField field) 308 throws IOException { 309 } 310 311 protected void writeByteField(Oop oop, ByteField field) 312 throws IOException { 313 } 314 315 protected void writeCharField(Oop oop, CharField field) 316 throws IOException { 317 } 318 319 protected void writeBooleanField(Oop oop, BooleanField field) 320 throws IOException { 321 } 322 323 protected void writeShortField(Oop oop, ShortField field) 324 throws IOException { 325 } 326 327 protected void writeIntField(Oop oop, IntField field) 328 throws IOException { 329 } 330 331 protected void writeLongField(Oop oop, LongField field) 332 throws IOException { 333 } 334 335 protected void writeFloatField(Oop oop, FloatField field) 336 throws IOException { 337 } 338 339 protected void writeDoubleField(Oop oop, DoubleField field) 340 throws IOException { 341 } 342 343 protected void writeObjectFooter(Oop oop) throws IOException { 344 } 345 346 protected void writeHeapFooter() throws IOException { 347 } 348 349 // HeapVisitor, OopVisitor methods can't throw any non-runtime 350 // exception. But, derived class write methods (which are called 351 // from visitor callbacks) may throw IOException. Hence, we throw 352 // RuntimeException with origianal IOException as cause from the 353 // visitor methods. This method gets back the original IOException 354 // (if any) and re-throws the same. 355 protected void handleRuntimeException(RuntimeException re) 356 throws IOException { 357 Throwable cause = re.getCause(); 358 if (cause != null && cause instanceof IOException) { 359 throw (IOException) cause; 360 } else { 361 // some other RuntimeException, just re-throw 362 throw re; 363 } 364 } 365 366 // whether a given oop is Java visible or hotspot internal? 367 protected boolean isJavaVisible(Oop oop) { 368 if (oop instanceof Instance || oop instanceof TypeArray) { 369 return true; 370 } else if (oop instanceof ObjArray) { 371 ObjArrayKlass oak = (ObjArrayKlass) oop.getKlass(); 372 Klass bottomKlass = oak.getBottomKlass(); 373 return bottomKlass instanceof InstanceKlass || 374 bottomKlass instanceof TypeArrayKlass; 375 } else { 376 return false; 377 } 378 } 379 380 protected Symbol javaLangClass; 381 protected Symbol javaLangString; 382 protected Symbol javaLangThread; 383 }