1 /* 2 * Copyright (c) 2004, 2019, 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 for (int i = 0; i < threads.getNumberOfThreads(); i++) { 133 JavaThread jt = threads.getJavaThreadAt(i); 134 if (jt.getThreadObj() != null) { 135 // Note that the thread serial number range is 1-to-N 136 writeJavaThread(jt, i + 1); 137 } 138 } 139 } 140 writeJavaThread(JavaThread jt, int index)141 protected void writeJavaThread(JavaThread jt, int index) 142 throws IOException { 143 } 144 writeGlobalJNIHandles()145 protected void writeGlobalJNIHandles() throws IOException { 146 JNIHandles handles = VM.getVM().getJNIHandles(); 147 OopStorage blk = handles.globalHandles(); 148 if (blk != null) { 149 try { 150 blk.oopsDo(new AddressVisitor() { 151 public void visitAddress(Address handleAddr) { 152 try { 153 if (handleAddr != null) { 154 writeGlobalJNIHandle(handleAddr); 155 } 156 } catch (IOException exp) { 157 throw new RuntimeException(exp); 158 } 159 } 160 public void visitCompOopAddress(Address handleAddr) { 161 throw new RuntimeException("Should not reach here. JNIHandles are not compressed"); 162 } 163 }); 164 } catch (RuntimeException re) { 165 handleRuntimeException(re); 166 } 167 } 168 } 169 writeGlobalJNIHandle(Address handleAddr)170 protected void writeGlobalJNIHandle(Address handleAddr) throws IOException { 171 } 172 writeHeapHeader()173 protected void writeHeapHeader() throws IOException { 174 } 175 176 // write non-Java-visible (hotspot internal) object writeInternalObject(Oop oop)177 protected void writeInternalObject(Oop oop) throws IOException { 178 } 179 180 // write Java primitive array writePrimitiveArray(TypeArray array)181 protected void writePrimitiveArray(TypeArray array) throws IOException { 182 writeObject(array); 183 } 184 185 // write Java object array writeObjectArray(ObjArray array)186 protected void writeObjectArray(ObjArray array) throws IOException { 187 writeObject(array); 188 } 189 writeInstance(Instance instance)190 protected void writeInstance(Instance instance) throws IOException { 191 writeObject(instance); 192 } 193 writeString(Instance instance)194 protected void writeString(Instance instance) throws IOException { 195 writeInstance(instance); 196 } 197 writeClass(Instance instance)198 protected void writeClass(Instance instance) throws IOException { 199 writeInstance(instance); 200 } 201 writeThread(Instance instance)202 protected void writeThread(Instance instance) throws IOException { 203 writeInstance(instance); 204 } 205 writeObject(Oop oop)206 protected void writeObject(Oop oop) throws IOException { 207 writeObjectHeader(oop); 208 writeObjectFields(oop); 209 writeObjectFooter(oop); 210 } 211 writeObjectHeader(Oop oop)212 protected void writeObjectHeader(Oop oop) throws IOException { 213 } 214 215 // write instance fields of given object writeObjectFields(final Oop oop)216 protected void writeObjectFields(final Oop oop) throws IOException { 217 try { 218 oop.iterate(new DefaultOopVisitor() { 219 public void doOop(OopField field, boolean isVMField) { 220 try { 221 writeReferenceField(oop, field); 222 } catch (IOException exp) { 223 throw new RuntimeException(exp); 224 } 225 } 226 227 public void doByte(ByteField field, boolean isVMField) { 228 try { 229 writeByteField(oop, field); 230 } catch (IOException exp) { 231 throw new RuntimeException(exp); 232 } 233 } 234 235 public void doChar(CharField field, boolean isVMField) { 236 try { 237 writeCharField(oop, field); 238 } catch (IOException exp) { 239 throw new RuntimeException(exp); 240 } 241 } 242 243 public void doBoolean(BooleanField field, boolean vField) { 244 try { 245 writeBooleanField(oop, field); 246 } catch (IOException exp) { 247 throw new RuntimeException(exp); 248 } 249 } 250 251 public void doShort(ShortField field, boolean isVMField) { 252 try { 253 writeShortField(oop, field); 254 } catch (IOException exp) { 255 throw new RuntimeException(exp); 256 } 257 } 258 259 public void doInt(IntField field, boolean isVMField) { 260 try { 261 writeIntField(oop, field); 262 } catch (IOException exp) { 263 throw new RuntimeException(exp); 264 } 265 } 266 267 public void doLong(LongField field, boolean isVMField) { 268 try { 269 writeLongField(oop, field); 270 } catch (IOException exp) { 271 throw new RuntimeException(exp); 272 } 273 } 274 275 public void doFloat(FloatField field, boolean isVMField) { 276 try { 277 writeFloatField(oop, field); 278 } catch (IOException exp) { 279 throw new RuntimeException(exp); 280 } 281 } 282 283 public void doDouble(DoubleField field, boolean vField) { 284 try { 285 writeDoubleField(oop, field); 286 } catch (IOException exp) { 287 throw new RuntimeException(exp); 288 } 289 } 290 }, false); 291 } catch (RuntimeException re) { 292 handleRuntimeException(re); 293 } 294 } 295 296 // write instance fields of given object writeObjectFields(final InstanceKlass oop)297 protected void writeObjectFields(final InstanceKlass oop) throws IOException { 298 try { 299 oop.iterateStaticFields(new DefaultOopVisitor() { 300 public void doOop(OopField field, boolean isVMField) { 301 try { 302 writeReferenceField(null, field); 303 } catch (IOException exp) { 304 throw new RuntimeException(exp); 305 } 306 } 307 308 public void doByte(ByteField field, boolean isVMField) { 309 try { 310 writeByteField(null, field); 311 } catch (IOException exp) { 312 throw new RuntimeException(exp); 313 } 314 } 315 316 public void doChar(CharField field, boolean isVMField) { 317 try { 318 writeCharField(null, field); 319 } catch (IOException exp) { 320 throw new RuntimeException(exp); 321 } 322 } 323 324 public void doBoolean(BooleanField field, boolean vField) { 325 try { 326 writeBooleanField(null, field); 327 } catch (IOException exp) { 328 throw new RuntimeException(exp); 329 } 330 } 331 332 public void doShort(ShortField field, boolean isVMField) { 333 try { 334 writeShortField(null, field); 335 } catch (IOException exp) { 336 throw new RuntimeException(exp); 337 } 338 } 339 340 public void doInt(IntField field, boolean isVMField) { 341 try { 342 writeIntField(null, field); 343 } catch (IOException exp) { 344 throw new RuntimeException(exp); 345 } 346 } 347 348 public void doLong(LongField field, boolean isVMField) { 349 try { 350 writeLongField(null, field); 351 } catch (IOException exp) { 352 throw new RuntimeException(exp); 353 } 354 } 355 356 public void doFloat(FloatField field, boolean isVMField) { 357 try { 358 writeFloatField(null, field); 359 } catch (IOException exp) { 360 throw new RuntimeException(exp); 361 } 362 } 363 364 public void doDouble(DoubleField field, boolean vField) { 365 try { 366 writeDoubleField(null, field); 367 } catch (IOException exp) { 368 throw new RuntimeException(exp); 369 } 370 } 371 }); 372 } catch (RuntimeException re) { 373 handleRuntimeException(re); 374 } 375 } 376 377 // object field writers writeReferenceField(Oop oop, OopField field)378 protected void writeReferenceField(Oop oop, OopField field) 379 throws IOException { 380 } 381 writeByteField(Oop oop, ByteField field)382 protected void writeByteField(Oop oop, ByteField field) 383 throws IOException { 384 } 385 writeCharField(Oop oop, CharField field)386 protected void writeCharField(Oop oop, CharField field) 387 throws IOException { 388 } 389 writeBooleanField(Oop oop, BooleanField field)390 protected void writeBooleanField(Oop oop, BooleanField field) 391 throws IOException { 392 } 393 writeShortField(Oop oop, ShortField field)394 protected void writeShortField(Oop oop, ShortField field) 395 throws IOException { 396 } 397 writeIntField(Oop oop, IntField field)398 protected void writeIntField(Oop oop, IntField field) 399 throws IOException { 400 } 401 writeLongField(Oop oop, LongField field)402 protected void writeLongField(Oop oop, LongField field) 403 throws IOException { 404 } 405 writeFloatField(Oop oop, FloatField field)406 protected void writeFloatField(Oop oop, FloatField field) 407 throws IOException { 408 } 409 writeDoubleField(Oop oop, DoubleField field)410 protected void writeDoubleField(Oop oop, DoubleField field) 411 throws IOException { 412 } 413 writeObjectFooter(Oop oop)414 protected void writeObjectFooter(Oop oop) throws IOException { 415 } 416 writeHeapFooter()417 protected void writeHeapFooter() throws IOException { 418 } 419 writeHeapRecordPrologue()420 protected void writeHeapRecordPrologue() throws IOException { 421 } 422 writeHeapRecordEpilogue()423 protected void writeHeapRecordEpilogue() throws IOException { 424 } 425 426 // HeapVisitor, OopVisitor methods can't throw any non-runtime 427 // exception. But, derived class write methods (which are called 428 // from visitor callbacks) may throw IOException. Hence, we throw 429 // RuntimeException with origianal IOException as cause from the 430 // visitor methods. This method gets back the original IOException 431 // (if any) and re-throws the same. handleRuntimeException(RuntimeException re)432 protected void handleRuntimeException(RuntimeException re) 433 throws IOException { 434 Throwable cause = re.getCause(); 435 if (cause != null && cause instanceof IOException) { 436 throw (IOException) cause; 437 } else { 438 // some other RuntimeException, just re-throw 439 throw re; 440 } 441 } 442 443 // whether a given oop is Java visible or hotspot internal? isJavaVisible(Oop oop)444 protected boolean isJavaVisible(Oop oop) { 445 if (oop instanceof Instance || oop instanceof TypeArray) { 446 return true; 447 } else if (oop instanceof ObjArray) { 448 ObjArrayKlass oak = (ObjArrayKlass) oop.getKlass(); 449 Klass bottomKlass = oak.getBottomKlass(); 450 return bottomKlass instanceof InstanceKlass || 451 bottomKlass instanceof TypeArrayKlass; 452 } else { 453 return false; 454 } 455 } 456 457 protected String javaLangClass; 458 protected String javaLangString; 459 protected String javaLangThread; 460 } 461