HprofReader.java revision 2415:e5605f29b00e
1/* 2 * Copyright (c) 1997, 2016, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 27/* 28 * The Original Code is HAT. The Initial Developer of the 29 * Original Code is Bill Foote, with contributions from others 30 * at JavaSoft/Sun. 31 */ 32 33package jdk.test.lib.hprof.parser; 34 35import java.io.*; 36import java.util.Date; 37import java.util.Hashtable; 38import jdk.test.lib.hprof.model.ArrayTypeCodes; 39import jdk.test.lib.hprof.model.*; 40 41/** 42 * Object that's used to read a hprof file. 43 * 44 * @author Bill Foote 45 */ 46 47public class HprofReader extends Reader /* imports */ implements ArrayTypeCodes { 48 49 final static int MAGIC_NUMBER = 0x4a415641; 50 // That's "JAVA", the first part of "JAVA PROFILE ..." 51 private final static String[] VERSIONS = { 52 " PROFILE 1.0\0", 53 " PROFILE 1.0.1\0", 54 " PROFILE 1.0.2\0", 55 }; 56 57 private final static int VERSION_JDK12BETA3 = 0; 58 private final static int VERSION_JDK12BETA4 = 1; 59 private final static int VERSION_JDK6 = 2; 60 // These version numbers are indices into VERSIONS. The instance data 61 // member version is set to one of these, and it drives decisions when 62 // reading the file. 63 // 64 // Version 1.0.1 added HPROF_GC_PRIM_ARRAY_DUMP, which requires no 65 // version-sensitive parsing. 66 // 67 // Version 1.0.1 changed the type of a constant pool entry from a signature 68 // to a typecode. 69 // 70 // Version 1.0.2 added HPROF_HEAP_DUMP_SEGMENT and HPROF_HEAP_DUMP_END 71 // to allow a large heap to be dumped as a sequence of heap dump segments. 72 // 73 // The HPROF agent in J2SE 1.2 through to 5.0 generate a version 1.0.1 74 // file. In Java SE 6.0 the version is either 1.0.1 or 1.0.2 depending on 75 // the size of the heap (normally it will be 1.0.1 but for multi-GB 76 // heaps the heap dump will not fit in a HPROF_HEAP_DUMP record so the 77 // dump is generated as version 1.0.2). 78 79 // 80 // Record types: 81 // 82 static final int HPROF_UTF8 = 0x01; 83 static final int HPROF_LOAD_CLASS = 0x02; 84 static final int HPROF_UNLOAD_CLASS = 0x03; 85 static final int HPROF_FRAME = 0x04; 86 static final int HPROF_TRACE = 0x05; 87 static final int HPROF_ALLOC_SITES = 0x06; 88 static final int HPROF_HEAP_SUMMARY = 0x07; 89 90 static final int HPROF_START_THREAD = 0x0a; 91 static final int HPROF_END_THREAD = 0x0b; 92 93 static final int HPROF_HEAP_DUMP = 0x0c; 94 95 static final int HPROF_CPU_SAMPLES = 0x0d; 96 static final int HPROF_CONTROL_SETTINGS = 0x0e; 97 static final int HPROF_LOCKSTATS_WAIT_TIME = 0x10; 98 static final int HPROF_LOCKSTATS_HOLD_TIME = 0x11; 99 100 static final int HPROF_GC_ROOT_UNKNOWN = 0xff; 101 static final int HPROF_GC_ROOT_JNI_GLOBAL = 0x01; 102 static final int HPROF_GC_ROOT_JNI_LOCAL = 0x02; 103 static final int HPROF_GC_ROOT_JAVA_FRAME = 0x03; 104 static final int HPROF_GC_ROOT_NATIVE_STACK = 0x04; 105 static final int HPROF_GC_ROOT_STICKY_CLASS = 0x05; 106 static final int HPROF_GC_ROOT_THREAD_BLOCK = 0x06; 107 static final int HPROF_GC_ROOT_MONITOR_USED = 0x07; 108 static final int HPROF_GC_ROOT_THREAD_OBJ = 0x08; 109 110 static final int HPROF_GC_CLASS_DUMP = 0x20; 111 static final int HPROF_GC_INSTANCE_DUMP = 0x21; 112 static final int HPROF_GC_OBJ_ARRAY_DUMP = 0x22; 113 static final int HPROF_GC_PRIM_ARRAY_DUMP = 0x23; 114 115 static final int HPROF_HEAP_DUMP_SEGMENT = 0x1c; 116 static final int HPROF_HEAP_DUMP_END = 0x2c; 117 118 private final static int T_CLASS = 2; 119 120 private int version; // The version of .hprof being read 121 122 private int debugLevel; 123 private long currPos; // Current position in the file 124 125 private int dumpsToSkip; 126 private boolean callStack; // If true, read the call stack of objects 127 128 private int identifierSize; // Size, in bytes, of identifiers. 129 private Hashtable<Long, String> names; 130 131 // Hashtable<Integer, ThreadObject>, used to map the thread sequence number 132 // (aka "serial number") to the thread object ID for 133 // HPROF_GC_ROOT_THREAD_OBJ. ThreadObject is a trivial inner class, 134 // at the end of this file. 135 private Hashtable<Integer, ThreadObject> threadObjects; 136 137 // Hashtable<Long, String>, maps class object ID to class name 138 // (with / converted to .) 139 private Hashtable<Long, String> classNameFromObjectID; 140 141 // Hashtable<Integer, Integer>, maps class serial # to class object ID 142 private Hashtable<Integer, String> classNameFromSerialNo; 143 144 // Hashtable<Long, StackFrame> maps stack frame ID to StackFrame. 145 // Null if we're not tracking them. 146 private Hashtable<Long, StackFrame> stackFrames; 147 148 // Hashtable<Integer, StackTrace> maps stack frame ID to StackTrace 149 // Null if we're not tracking them. 150 private Hashtable<Integer, StackTrace> stackTraces; 151 152 private Snapshot snapshot; 153 154 public static boolean verifyMagicNumber(int numberRead) { 155 return (numberRead == MAGIC_NUMBER); 156 } 157 158 public HprofReader(String fileName, PositionDataInputStream in, 159 int dumpNumber, boolean callStack, int debugLevel) 160 throws IOException { 161 super(in); 162 RandomAccessFile file = new RandomAccessFile(fileName, "r"); 163 this.snapshot = new Snapshot(MappedReadBuffer.create(file)); 164 this.dumpsToSkip = dumpNumber - 1; 165 this.callStack = callStack; 166 this.debugLevel = debugLevel; 167 names = new Hashtable<Long, String>(); 168 threadObjects = new Hashtable<Integer, ThreadObject>(43); 169 classNameFromObjectID = new Hashtable<Long, String>(); 170 if (callStack) { 171 stackFrames = new Hashtable<Long, StackFrame>(43); 172 stackTraces = new Hashtable<Integer, StackTrace>(43); 173 classNameFromSerialNo = new Hashtable<Integer, String>(); 174 } 175 } 176 177 public Snapshot read() throws IOException { 178 currPos = 4; // 4 because of the magic number 179 version = readVersionHeader(); 180 identifierSize = in.readInt(); 181 snapshot.setIdentifierSize(identifierSize); 182 if (version >= VERSION_JDK12BETA4) { 183 snapshot.setNewStyleArrayClass(true); 184 } else { 185 snapshot.setNewStyleArrayClass(false); 186 } 187 188 currPos += 4; 189 if (identifierSize != 4 && identifierSize != 8) { 190 throw new IOException("I'm sorry, but I can't deal with an identifier size of " + identifierSize + ". I can only deal with 4 or 8."); 191 } 192 System.out.println("Dump file created " + (new Date(in.readLong()))); 193 currPos += 8; 194 195 for (;;) { 196 int type; 197 try { 198 type = in.readUnsignedByte(); 199 } catch (EOFException ignored) { 200 break; 201 } 202 in.readInt(); // Timestamp of this record 203 // Length of record: readInt() will return negative value for record 204 // length >2GB. so store 32bit value in long to keep it unsigned. 205 long length = in.readInt() & 0xffffffffL; 206 if (debugLevel > 0) { 207 System.out.println("Read record type " + type 208 + ", length " + length 209 + " at position " + toHex(currPos)); 210 } 211 if (length < 0) { 212 throw new IOException("Bad record length of " + length 213 + " at byte " + toHex(currPos+5) 214 + " of file."); 215 } 216 currPos += 9 + length; 217 switch (type) { 218 case HPROF_UTF8: { 219 long id = readID(); 220 byte[] chars = new byte[(int)length - identifierSize]; 221 in.readFully(chars); 222 names.put(id, new String(chars)); 223 break; 224 } 225 case HPROF_LOAD_CLASS: { 226 int serialNo = in.readInt(); // Not used 227 long classID = readID(); 228 int stackTraceSerialNo = in.readInt(); 229 long classNameID = readID(); 230 Long classIdI = classID; 231 String nm = getNameFromID(classNameID).replace('/', '.'); 232 classNameFromObjectID.put(classIdI, nm); 233 if (classNameFromSerialNo != null) { 234 classNameFromSerialNo.put(serialNo, nm); 235 } 236 break; 237 } 238 239 case HPROF_HEAP_DUMP: { 240 if (dumpsToSkip <= 0) { 241 try { 242 readHeapDump(length, currPos); 243 } catch (EOFException exp) { 244 handleEOF(exp, snapshot); 245 } 246 if (debugLevel > 0) { 247 System.out.println(" Finished processing instances in heap dump."); 248 } 249 return snapshot; 250 } else { 251 dumpsToSkip--; 252 skipBytes(length); 253 } 254 break; 255 } 256 257 case HPROF_HEAP_DUMP_END: { 258 if (version >= VERSION_JDK6) { 259 if (dumpsToSkip <= 0) { 260 skipBytes(length); // should be no-op 261 return snapshot; 262 } else { 263 // skip this dump (of the end record for a sequence of dump segments) 264 dumpsToSkip--; 265 } 266 } else { 267 // HPROF_HEAP_DUMP_END only recognized in >= 1.0.2 268 warn("Ignoring unrecognized record type " + type); 269 } 270 skipBytes(length); // should be no-op 271 break; 272 } 273 274 case HPROF_HEAP_DUMP_SEGMENT: { 275 if (version >= VERSION_JDK6) { 276 if (dumpsToSkip <= 0) { 277 try { 278 // read the dump segment 279 readHeapDump(length, currPos); 280 } catch (EOFException exp) { 281 handleEOF(exp, snapshot); 282 } 283 } else { 284 // all segments comprising the heap dump will be skipped 285 skipBytes(length); 286 } 287 } else { 288 // HPROF_HEAP_DUMP_SEGMENT only recognized in >= 1.0.2 289 warn("Ignoring unrecognized record type " + type); 290 skipBytes(length); 291 } 292 break; 293 } 294 295 case HPROF_FRAME: { 296 if (stackFrames == null) { 297 skipBytes(length); 298 } else { 299 long id = readID(); 300 String methodName = getNameFromID(readID()); 301 String methodSig = getNameFromID(readID()); 302 String sourceFile = getNameFromID(readID()); 303 int classSer = in.readInt(); 304 String className = classNameFromSerialNo.get(classSer); 305 int lineNumber = in.readInt(); 306 if (lineNumber < StackFrame.LINE_NUMBER_NATIVE) { 307 warn("Weird stack frame line number: " + lineNumber); 308 lineNumber = StackFrame.LINE_NUMBER_UNKNOWN; 309 } 310 stackFrames.put(id, 311 new StackFrame(methodName, methodSig, 312 className, sourceFile, 313 lineNumber)); 314 } 315 break; 316 } 317 case HPROF_TRACE: { 318 if (stackTraces == null) { 319 skipBytes(length); 320 } else { 321 int serialNo = in.readInt(); 322 int threadSeq = in.readInt(); // Not used 323 StackFrame[] frames = new StackFrame[in.readInt()]; 324 for (int i = 0; i < frames.length; i++) { 325 long fid = readID(); 326 frames[i] = stackFrames.get(fid); 327 if (frames[i] == null) { 328 throw new IOException("Stack frame " + toHex(fid) + " not found"); 329 } 330 } 331 stackTraces.put(serialNo, 332 new StackTrace(frames)); 333 } 334 break; 335 } 336 case HPROF_UNLOAD_CLASS: 337 case HPROF_ALLOC_SITES: 338 case HPROF_START_THREAD: 339 case HPROF_END_THREAD: 340 case HPROF_HEAP_SUMMARY: 341 case HPROF_CPU_SAMPLES: 342 case HPROF_CONTROL_SETTINGS: 343 case HPROF_LOCKSTATS_WAIT_TIME: 344 case HPROF_LOCKSTATS_HOLD_TIME: 345 { 346 // Ignore these record types 347 skipBytes(length); 348 break; 349 } 350 default: { 351 skipBytes(length); 352 warn("Ignoring unrecognized record type " + type); 353 } 354 } 355 } 356 357 return snapshot; 358 } 359 360 private void skipBytes(long length) throws IOException { 361 while (length > 0) { 362 long skipped = in.skip(length); 363 if (skipped == 0) { 364 // EOF or other problem, throw exception 365 throw new EOFException("Couldn't skip enough bytes"); 366 } 367 length -= skipped; 368 } 369 } 370 371 private int readVersionHeader() throws IOException { 372 int candidatesLeft = VERSIONS.length; 373 boolean[] matched = new boolean[VERSIONS.length]; 374 for (int i = 0; i < candidatesLeft; i++) { 375 matched[i] = true; 376 } 377 378 int pos = 0; 379 while (candidatesLeft > 0) { 380 char c = (char) in.readByte(); 381 currPos++; 382 for (int i = 0; i < VERSIONS.length; i++) { 383 if (matched[i]) { 384 if (c != VERSIONS[i].charAt(pos)) { // Not matched 385 matched[i] = false; 386 --candidatesLeft; 387 } else if (pos == VERSIONS[i].length() - 1) { // Full match 388 return i; 389 } 390 } 391 } 392 ++pos; 393 } 394 throw new IOException("Version string not recognized at byte " + (pos+3)); 395 } 396 397 private void readHeapDump(long bytesLeft, long posAtEnd) throws IOException { 398 while (bytesLeft > 0) { 399 int type = in.readUnsignedByte(); 400 if (debugLevel > 0) { 401 System.out.println(" Read heap sub-record type " + type 402 + " at position " 403 + toHex(posAtEnd - bytesLeft)); 404 } 405 bytesLeft--; 406 switch(type) { 407 case HPROF_GC_ROOT_UNKNOWN: { 408 long id = readID(); 409 bytesLeft -= identifierSize; 410 snapshot.addRoot(new Root(id, 0, Root.UNKNOWN, "")); 411 break; 412 } 413 case HPROF_GC_ROOT_THREAD_OBJ: { 414 long id = readID(); 415 int threadSeq = in.readInt(); 416 int stackSeq = in.readInt(); 417 bytesLeft -= identifierSize + 8; 418 threadObjects.put(threadSeq, 419 new ThreadObject(id, stackSeq)); 420 break; 421 } 422 case HPROF_GC_ROOT_JNI_GLOBAL: { 423 long id = readID(); 424 long globalRefId = readID(); // Ignored, for now 425 bytesLeft -= 2*identifierSize; 426 snapshot.addRoot(new Root(id, 0, Root.NATIVE_STATIC, "")); 427 break; 428 } 429 case HPROF_GC_ROOT_JNI_LOCAL: { 430 long id = readID(); 431 int threadSeq = in.readInt(); 432 int depth = in.readInt(); 433 bytesLeft -= identifierSize + 8; 434 ThreadObject to = getThreadObjectFromSequence(threadSeq); 435 StackTrace st = getStackTraceFromSerial(to.stackSeq); 436 if (st != null) { 437 st = st.traceForDepth(depth+1); 438 } 439 snapshot.addRoot(new Root(id, to.threadId, 440 Root.NATIVE_LOCAL, "", st)); 441 break; 442 } 443 case HPROF_GC_ROOT_JAVA_FRAME: { 444 long id = readID(); 445 int threadSeq = in.readInt(); 446 int depth = in.readInt(); 447 bytesLeft -= identifierSize + 8; 448 ThreadObject to = getThreadObjectFromSequence(threadSeq); 449 StackTrace st = getStackTraceFromSerial(to.stackSeq); 450 if (st != null) { 451 st = st.traceForDepth(depth+1); 452 } 453 snapshot.addRoot(new Root(id, to.threadId, 454 Root.JAVA_LOCAL, "", st)); 455 break; 456 } 457 case HPROF_GC_ROOT_NATIVE_STACK: { 458 long id = readID(); 459 int threadSeq = in.readInt(); 460 bytesLeft -= identifierSize + 4; 461 ThreadObject to = getThreadObjectFromSequence(threadSeq); 462 StackTrace st = getStackTraceFromSerial(to.stackSeq); 463 snapshot.addRoot(new Root(id, to.threadId, 464 Root.NATIVE_STACK, "", st)); 465 break; 466 } 467 case HPROF_GC_ROOT_STICKY_CLASS: { 468 long id = readID(); 469 bytesLeft -= identifierSize; 470 snapshot.addRoot(new Root(id, 0, Root.SYSTEM_CLASS, "")); 471 break; 472 } 473 case HPROF_GC_ROOT_THREAD_BLOCK: { 474 long id = readID(); 475 int threadSeq = in.readInt(); 476 bytesLeft -= identifierSize + 4; 477 ThreadObject to = getThreadObjectFromSequence(threadSeq); 478 StackTrace st = getStackTraceFromSerial(to.stackSeq); 479 snapshot.addRoot(new Root(id, to.threadId, 480 Root.THREAD_BLOCK, "", st)); 481 break; 482 } 483 case HPROF_GC_ROOT_MONITOR_USED: { 484 long id = readID(); 485 bytesLeft -= identifierSize; 486 snapshot.addRoot(new Root(id, 0, Root.BUSY_MONITOR, "")); 487 break; 488 } 489 case HPROF_GC_CLASS_DUMP: { 490 int bytesRead = readClass(); 491 bytesLeft -= bytesRead; 492 break; 493 } 494 case HPROF_GC_INSTANCE_DUMP: { 495 int bytesRead = readInstance(); 496 bytesLeft -= bytesRead; 497 break; 498 } 499 case HPROF_GC_OBJ_ARRAY_DUMP: { 500 long bytesRead = readArray(false); 501 bytesLeft -= bytesRead; 502 break; 503 } 504 case HPROF_GC_PRIM_ARRAY_DUMP: { 505 long bytesRead = readArray(true); 506 bytesLeft -= bytesRead; 507 break; 508 } 509 default: { 510 throw new IOException("Unrecognized heap dump sub-record type: " + type); 511 } 512 } 513 } 514 if (bytesLeft != 0) { 515 warn("Error reading heap dump or heap dump segment: Byte count is " + bytesLeft + " instead of 0"); 516 skipBytes(bytesLeft); 517 } 518 if (debugLevel > 0) { 519 System.out.println(" Finished heap sub-records."); 520 } 521 } 522 523 private long readID() throws IOException { 524 return (identifierSize == 4)? 525 (Snapshot.SMALL_ID_MASK & (long)in.readInt()) : in.readLong(); 526 } 527 528 // 529 // Read a java value. If result is non-null, it's expected to be an 530 // array of one element. We use it to fake multiple return values. 531 // @returns the number of bytes read 532 // 533 private int readValue(JavaThing[] resultArr) throws IOException { 534 byte type = in.readByte(); 535 return 1 + readValueForType(type, resultArr); 536 } 537 538 private int readValueForType(byte type, JavaThing[] resultArr) 539 throws IOException { 540 if (version >= VERSION_JDK12BETA4) { 541 type = signatureFromTypeId(type); 542 } 543 return readValueForTypeSignature(type, resultArr); 544 } 545 546 private int readValueForTypeSignature(byte type, JavaThing[] resultArr) 547 throws IOException { 548 switch (type) { 549 case '[': 550 case 'L': { 551 long id = readID(); 552 if (resultArr != null) { 553 resultArr[0] = new JavaObjectRef(id); 554 } 555 return identifierSize; 556 } 557 case 'Z': { 558 int b = in.readByte(); 559 if (b != 0 && b != 1) { 560 warn("Illegal boolean value read"); 561 } 562 if (resultArr != null) { 563 resultArr[0] = new JavaBoolean(b != 0); 564 } 565 return 1; 566 } 567 case 'B': { 568 byte b = in.readByte(); 569 if (resultArr != null) { 570 resultArr[0] = new JavaByte(b); 571 } 572 return 1; 573 } 574 case 'S': { 575 short s = in.readShort(); 576 if (resultArr != null) { 577 resultArr[0] = new JavaShort(s); 578 } 579 return 2; 580 } 581 case 'C': { 582 char ch = in.readChar(); 583 if (resultArr != null) { 584 resultArr[0] = new JavaChar(ch); 585 } 586 return 2; 587 } 588 case 'I': { 589 int val = in.readInt(); 590 if (resultArr != null) { 591 resultArr[0] = new JavaInt(val); 592 } 593 return 4; 594 } 595 case 'J': { 596 long val = in.readLong(); 597 if (resultArr != null) { 598 resultArr[0] = new JavaLong(val); 599 } 600 return 8; 601 } 602 case 'F': { 603 float val = in.readFloat(); 604 if (resultArr != null) { 605 resultArr[0] = new JavaFloat(val); 606 } 607 return 4; 608 } 609 case 'D': { 610 double val = in.readDouble(); 611 if (resultArr != null) { 612 resultArr[0] = new JavaDouble(val); 613 } 614 return 8; 615 } 616 default: { 617 throw new IOException("Bad value signature: " + type); 618 } 619 } 620 } 621 622 private ThreadObject getThreadObjectFromSequence(int threadSeq) 623 throws IOException { 624 ThreadObject to = threadObjects.get(threadSeq); 625 if (to == null) { 626 throw new IOException("Thread " + threadSeq + 627 " not found for JNI local ref"); 628 } 629 return to; 630 } 631 632 private String getNameFromID(long id) throws IOException { 633 return getNameFromID(Long.valueOf(id)); 634 } 635 636 private String getNameFromID(Long id) throws IOException { 637 if (id.longValue() == 0L) { 638 return ""; 639 } 640 String result = names.get(id); 641 if (result == null) { 642 warn("Name not found at " + toHex(id.longValue())); 643 return "unresolved name " + toHex(id.longValue()); 644 } 645 return result; 646 } 647 648 private StackTrace getStackTraceFromSerial(int ser) throws IOException { 649 if (stackTraces == null) { 650 return null; 651 } 652 StackTrace result = stackTraces.get(ser); 653 if (result == null) { 654 warn("Stack trace not found for serial # " + ser); 655 } 656 return result; 657 } 658 659 // 660 // Handle a HPROF_GC_CLASS_DUMP 661 // Return number of bytes read 662 // 663 private int readClass() throws IOException { 664 long id = readID(); 665 StackTrace stackTrace = getStackTraceFromSerial(in.readInt()); 666 long superId = readID(); 667 long classLoaderId = readID(); 668 long signersId = readID(); 669 long protDomainId = readID(); 670 long reserved1 = readID(); 671 long reserved2 = readID(); 672 int instanceSize = in.readInt(); 673 int bytesRead = 7 * identifierSize + 8; 674 675 int numConstPoolEntries = in.readUnsignedShort(); 676 bytesRead += 2; 677 for (int i = 0; i < numConstPoolEntries; i++) { 678 int index = in.readUnsignedShort(); // unused 679 bytesRead += 2; 680 bytesRead += readValue(null); // We ignore the values 681 } 682 683 int numStatics = in.readUnsignedShort(); 684 bytesRead += 2; 685 JavaThing[] valueBin = new JavaThing[1]; 686 JavaStatic[] statics = new JavaStatic[numStatics]; 687 for (int i = 0; i < numStatics; i++) { 688 long nameId = readID(); 689 bytesRead += identifierSize; 690 byte type = in.readByte(); 691 bytesRead++; 692 bytesRead += readValueForType(type, valueBin); 693 String fieldName = getNameFromID(nameId); 694 if (version >= VERSION_JDK12BETA4) { 695 type = signatureFromTypeId(type); 696 } 697 String signature = "" + ((char) type); 698 JavaField f = new JavaField(fieldName, signature); 699 statics[i] = new JavaStatic(f, valueBin[0]); 700 } 701 702 int numFields = in.readUnsignedShort(); 703 bytesRead += 2; 704 JavaField[] fields = new JavaField[numFields]; 705 for (int i = 0; i < numFields; i++) { 706 long nameId = readID(); 707 bytesRead += identifierSize; 708 byte type = in.readByte(); 709 bytesRead++; 710 String fieldName = getNameFromID(nameId); 711 if (version >= VERSION_JDK12BETA4) { 712 type = signatureFromTypeId(type); 713 } 714 String signature = "" + ((char) type); 715 fields[i] = new JavaField(fieldName, signature); 716 } 717 String name = classNameFromObjectID.get(id); 718 if (name == null) { 719 warn("Class name not found for " + toHex(id)); 720 name = "unknown-name@" + toHex(id); 721 } 722 JavaClass c = new JavaClass(id, name, superId, classLoaderId, signersId, 723 protDomainId, fields, statics, 724 instanceSize); 725 snapshot.addClass(id, c); 726 snapshot.setSiteTrace(c, stackTrace); 727 728 return bytesRead; 729 } 730 731 private String toHex(long addr) { 732 return jdk.test.lib.hprof.util.Misc.toHex(addr); 733 } 734 735 // 736 // Handle a HPROF_GC_INSTANCE_DUMP 737 // Return number of bytes read 738 // 739 private int readInstance() throws IOException { 740 long start = in.position(); 741 long id = readID(); 742 StackTrace stackTrace = getStackTraceFromSerial(in.readInt()); 743 long classID = readID(); 744 JavaClass searchedClass = snapshot.findClass( 745 "0x" + Long.toHexString(classID)); 746 if (searchedClass == null) { 747 throw new IOException( 748 "Class Record for 0x" + Long.toHexString(classID) + " not found"); 749 } 750 int bytesFollowing = in.readInt(); 751 int bytesRead = (2 * identifierSize) + 8 + bytesFollowing; 752 JavaObject jobj = new JavaObject(classID, start); 753 skipBytes(bytesFollowing); 754 snapshot.addHeapObject(id, jobj); 755 snapshot.setSiteTrace(jobj, stackTrace); 756 return bytesRead; 757 } 758 759 // 760 // Handle a HPROF_GC_OBJ_ARRAY_DUMP or HPROF_GC_PRIM_ARRAY_DUMP 761 // Return number of bytes read 762 // 763 private long readArray(boolean isPrimitive) throws IOException { 764 long start = in.position(); 765 long id = readID(); 766 StackTrace stackTrace = getStackTraceFromSerial(in.readInt()); 767 int num = in.readInt(); 768 long bytesRead = identifierSize + 8; 769 long elementClassID; 770 if (isPrimitive) { 771 elementClassID = in.readByte(); 772 bytesRead++; 773 } else { 774 elementClassID = readID(); 775 bytesRead += identifierSize; 776 } 777 778 // Check for primitive arrays: 779 byte primitiveSignature = 0x00; 780 int elSize = 0; 781 if (isPrimitive || version < VERSION_JDK12BETA4) { 782 switch ((int)elementClassID) { 783 case T_BOOLEAN: { 784 primitiveSignature = (byte) 'Z'; 785 elSize = 1; 786 break; 787 } 788 case T_CHAR: { 789 primitiveSignature = (byte) 'C'; 790 elSize = 2; 791 break; 792 } 793 case T_FLOAT: { 794 primitiveSignature = (byte) 'F'; 795 elSize = 4; 796 break; 797 } 798 case T_DOUBLE: { 799 primitiveSignature = (byte) 'D'; 800 elSize = 8; 801 break; 802 } 803 case T_BYTE: { 804 primitiveSignature = (byte) 'B'; 805 elSize = 1; 806 break; 807 } 808 case T_SHORT: { 809 primitiveSignature = (byte) 'S'; 810 elSize = 2; 811 break; 812 } 813 case T_INT: { 814 primitiveSignature = (byte) 'I'; 815 elSize = 4; 816 break; 817 } 818 case T_LONG: { 819 primitiveSignature = (byte) 'J'; 820 elSize = 8; 821 break; 822 } 823 } 824 if (version >= VERSION_JDK12BETA4 && primitiveSignature == 0x00) { 825 throw new IOException("Unrecognized typecode: " 826 + elementClassID); 827 } 828 } 829 if (primitiveSignature != 0x00) { 830 long size = elSize * (long)num; 831 bytesRead += size; 832 JavaValueArray va = new JavaValueArray(primitiveSignature, start); 833 skipBytes(size); 834 snapshot.addHeapObject(id, va); 835 snapshot.setSiteTrace(va, stackTrace); 836 } else { 837 long sz = (long)num * identifierSize; 838 bytesRead += sz; 839 JavaObjectArray arr = new JavaObjectArray(elementClassID, start); 840 skipBytes(sz); 841 snapshot.addHeapObject(id, arr); 842 snapshot.setSiteTrace(arr, stackTrace); 843 } 844 return bytesRead; 845 } 846 847 private byte signatureFromTypeId(byte typeId) throws IOException { 848 switch (typeId) { 849 case T_CLASS: { 850 return (byte) 'L'; 851 } 852 case T_BOOLEAN: { 853 return (byte) 'Z'; 854 } 855 case T_CHAR: { 856 return (byte) 'C'; 857 } 858 case T_FLOAT: { 859 return (byte) 'F'; 860 } 861 case T_DOUBLE: { 862 return (byte) 'D'; 863 } 864 case T_BYTE: { 865 return (byte) 'B'; 866 } 867 case T_SHORT: { 868 return (byte) 'S'; 869 } 870 case T_INT: { 871 return (byte) 'I'; 872 } 873 case T_LONG: { 874 return (byte) 'J'; 875 } 876 default: { 877 throw new IOException("Invalid type id of " + typeId); 878 } 879 } 880 } 881 882 private void handleEOF(EOFException exp, Snapshot snapshot) { 883 if (debugLevel > 0) { 884 exp.printStackTrace(); 885 } 886 warn("Unexpected EOF. Will miss information..."); 887 // we have EOF, we have to tolerate missing references 888 snapshot.setUnresolvedObjectsOK(true); 889 } 890 891 private void warn(String msg) { 892 System.out.println("WARNING: " + msg); 893 } 894 895 // 896 // A trivial data-holder class for HPROF_GC_ROOT_THREAD_OBJ. 897 // 898 private class ThreadObject { 899 900 long threadId; 901 int stackSeq; 902 903 ThreadObject(long threadId, int stackSeq) { 904 this.threadId = threadId; 905 this.stackSeq = stackSeq; 906 } 907 } 908 909} 910