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