HprofReader.java revision 2224:2a8815d86b93
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 HprofReader(String fileName, PositionDataInputStream in, 155 int dumpNumber, boolean callStack, int debugLevel) 156 throws IOException { 157 super(in); 158 RandomAccessFile file = new RandomAccessFile(fileName, "r"); 159 this.snapshot = new Snapshot(MappedReadBuffer.create(file)); 160 this.dumpsToSkip = dumpNumber - 1; 161 this.callStack = callStack; 162 this.debugLevel = debugLevel; 163 names = new Hashtable<Long, String>(); 164 threadObjects = new Hashtable<Integer, ThreadObject>(43); 165 classNameFromObjectID = new Hashtable<Long, String>(); 166 if (callStack) { 167 stackFrames = new Hashtable<Long, StackFrame>(43); 168 stackTraces = new Hashtable<Integer, StackTrace>(43); 169 classNameFromSerialNo = new Hashtable<Integer, String>(); 170 } 171 } 172 173 public Snapshot read() throws IOException { 174 currPos = 4; // 4 because of the magic number 175 version = readVersionHeader(); 176 identifierSize = in.readInt(); 177 snapshot.setIdentifierSize(identifierSize); 178 if (version >= VERSION_JDK12BETA4) { 179 snapshot.setNewStyleArrayClass(true); 180 } else { 181 snapshot.setNewStyleArrayClass(false); 182 } 183 184 currPos += 4; 185 if (identifierSize != 4 && identifierSize != 8) { 186 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."); 187 } 188 System.out.println("Dump file created " + (new Date(in.readLong()))); 189 currPos += 8; 190 191 for (;;) { 192 int type; 193 try { 194 type = in.readUnsignedByte(); 195 } catch (EOFException ignored) { 196 break; 197 } 198 in.readInt(); // Timestamp of this record 199 // Length of record: readInt() will return negative value for record 200 // length >2GB. so store 32bit value in long to keep it unsigned. 201 long length = in.readInt() & 0xffffffffL; 202 if (debugLevel > 0) { 203 System.out.println("Read record type " + type 204 + ", length " + length 205 + " at position " + toHex(currPos)); 206 } 207 if (length < 0) { 208 throw new IOException("Bad record length of " + length 209 + " at byte " + toHex(currPos+5) 210 + " of file."); 211 } 212 currPos += 9 + length; 213 switch (type) { 214 case HPROF_UTF8: { 215 long id = readID(); 216 byte[] chars = new byte[(int)length - identifierSize]; 217 in.readFully(chars); 218 names.put(id, new String(chars)); 219 break; 220 } 221 case HPROF_LOAD_CLASS: { 222 int serialNo = in.readInt(); // Not used 223 long classID = readID(); 224 int stackTraceSerialNo = in.readInt(); 225 long classNameID = readID(); 226 Long classIdI = classID; 227 String nm = getNameFromID(classNameID).replace('/', '.'); 228 classNameFromObjectID.put(classIdI, nm); 229 if (classNameFromSerialNo != null) { 230 classNameFromSerialNo.put(serialNo, nm); 231 } 232 break; 233 } 234 235 case HPROF_HEAP_DUMP: { 236 if (dumpsToSkip <= 0) { 237 try { 238 readHeapDump(length, currPos); 239 } catch (EOFException exp) { 240 handleEOF(exp, snapshot); 241 } 242 if (debugLevel > 0) { 243 System.out.println(" Finished processing instances in heap dump."); 244 } 245 return snapshot; 246 } else { 247 dumpsToSkip--; 248 skipBytes(length); 249 } 250 break; 251 } 252 253 case HPROF_HEAP_DUMP_END: { 254 if (version >= VERSION_JDK6) { 255 if (dumpsToSkip <= 0) { 256 skipBytes(length); // should be no-op 257 return snapshot; 258 } else { 259 // skip this dump (of the end record for a sequence of dump segments) 260 dumpsToSkip--; 261 } 262 } else { 263 // HPROF_HEAP_DUMP_END only recognized in >= 1.0.2 264 warn("Ignoring unrecognized record type " + type); 265 } 266 skipBytes(length); // should be no-op 267 break; 268 } 269 270 case HPROF_HEAP_DUMP_SEGMENT: { 271 if (version >= VERSION_JDK6) { 272 if (dumpsToSkip <= 0) { 273 try { 274 // read the dump segment 275 readHeapDump(length, currPos); 276 } catch (EOFException exp) { 277 handleEOF(exp, snapshot); 278 } 279 } else { 280 // all segments comprising the heap dump will be skipped 281 skipBytes(length); 282 } 283 } else { 284 // HPROF_HEAP_DUMP_SEGMENT only recognized in >= 1.0.2 285 warn("Ignoring unrecognized record type " + type); 286 skipBytes(length); 287 } 288 break; 289 } 290 291 case HPROF_FRAME: { 292 if (stackFrames == null) { 293 skipBytes(length); 294 } else { 295 long id = readID(); 296 String methodName = getNameFromID(readID()); 297 String methodSig = getNameFromID(readID()); 298 String sourceFile = getNameFromID(readID()); 299 int classSer = in.readInt(); 300 String className = classNameFromSerialNo.get(classSer); 301 int lineNumber = in.readInt(); 302 if (lineNumber < StackFrame.LINE_NUMBER_NATIVE) { 303 warn("Weird stack frame line number: " + lineNumber); 304 lineNumber = StackFrame.LINE_NUMBER_UNKNOWN; 305 } 306 stackFrames.put(id, 307 new StackFrame(methodName, methodSig, 308 className, sourceFile, 309 lineNumber)); 310 } 311 break; 312 } 313 case HPROF_TRACE: { 314 if (stackTraces == null) { 315 skipBytes(length); 316 } else { 317 int serialNo = in.readInt(); 318 int threadSeq = in.readInt(); // Not used 319 StackFrame[] frames = new StackFrame[in.readInt()]; 320 for (int i = 0; i < frames.length; i++) { 321 long fid = readID(); 322 frames[i] = stackFrames.get(fid); 323 if (frames[i] == null) { 324 throw new IOException("Stack frame " + toHex(fid) + " not found"); 325 } 326 } 327 stackTraces.put(serialNo, 328 new StackTrace(frames)); 329 } 330 break; 331 } 332 case HPROF_UNLOAD_CLASS: 333 case HPROF_ALLOC_SITES: 334 case HPROF_START_THREAD: 335 case HPROF_END_THREAD: 336 case HPROF_HEAP_SUMMARY: 337 case HPROF_CPU_SAMPLES: 338 case HPROF_CONTROL_SETTINGS: 339 case HPROF_LOCKSTATS_WAIT_TIME: 340 case HPROF_LOCKSTATS_HOLD_TIME: 341 { 342 // Ignore these record types 343 skipBytes(length); 344 break; 345 } 346 default: { 347 skipBytes(length); 348 warn("Ignoring unrecognized record type " + type); 349 } 350 } 351 } 352 353 return snapshot; 354 } 355 356 private void skipBytes(long length) throws IOException { 357 while (length > 0) { 358 long skipped = in.skip(length); 359 if (skipped == 0) { 360 // EOF or other problem, throw exception 361 throw new EOFException("Couldn't skip enough bytes"); 362 } 363 length -= skipped; 364 } 365 } 366 367 private int readVersionHeader() throws IOException { 368 int candidatesLeft = VERSIONS.length; 369 boolean[] matched = new boolean[VERSIONS.length]; 370 for (int i = 0; i < candidatesLeft; i++) { 371 matched[i] = true; 372 } 373 374 int pos = 0; 375 while (candidatesLeft > 0) { 376 char c = (char) in.readByte(); 377 currPos++; 378 for (int i = 0; i < VERSIONS.length; i++) { 379 if (matched[i]) { 380 if (c != VERSIONS[i].charAt(pos)) { // Not matched 381 matched[i] = false; 382 --candidatesLeft; 383 } else if (pos == VERSIONS[i].length() - 1) { // Full match 384 return i; 385 } 386 } 387 } 388 ++pos; 389 } 390 throw new IOException("Version string not recognized at byte " + (pos+3)); 391 } 392 393 private void readHeapDump(long bytesLeft, long posAtEnd) throws IOException { 394 while (bytesLeft > 0) { 395 int type = in.readUnsignedByte(); 396 if (debugLevel > 0) { 397 System.out.println(" Read heap sub-record type " + type 398 + " at position " 399 + toHex(posAtEnd - bytesLeft)); 400 } 401 bytesLeft--; 402 switch(type) { 403 case HPROF_GC_ROOT_UNKNOWN: { 404 long id = readID(); 405 bytesLeft -= identifierSize; 406 snapshot.addRoot(new Root(id, 0, Root.UNKNOWN, "")); 407 break; 408 } 409 case HPROF_GC_ROOT_THREAD_OBJ: { 410 long id = readID(); 411 int threadSeq = in.readInt(); 412 int stackSeq = in.readInt(); 413 bytesLeft -= identifierSize + 8; 414 threadObjects.put(threadSeq, 415 new ThreadObject(id, stackSeq)); 416 break; 417 } 418 case HPROF_GC_ROOT_JNI_GLOBAL: { 419 long id = readID(); 420 long globalRefId = readID(); // Ignored, for now 421 bytesLeft -= 2*identifierSize; 422 snapshot.addRoot(new Root(id, 0, Root.NATIVE_STATIC, "")); 423 break; 424 } 425 case HPROF_GC_ROOT_JNI_LOCAL: { 426 long id = readID(); 427 int threadSeq = in.readInt(); 428 int depth = in.readInt(); 429 bytesLeft -= identifierSize + 8; 430 ThreadObject to = getThreadObjectFromSequence(threadSeq); 431 StackTrace st = getStackTraceFromSerial(to.stackSeq); 432 if (st != null) { 433 st = st.traceForDepth(depth+1); 434 } 435 snapshot.addRoot(new Root(id, to.threadId, 436 Root.NATIVE_LOCAL, "", st)); 437 break; 438 } 439 case HPROF_GC_ROOT_JAVA_FRAME: { 440 long id = readID(); 441 int threadSeq = in.readInt(); 442 int depth = in.readInt(); 443 bytesLeft -= identifierSize + 8; 444 ThreadObject to = getThreadObjectFromSequence(threadSeq); 445 StackTrace st = getStackTraceFromSerial(to.stackSeq); 446 if (st != null) { 447 st = st.traceForDepth(depth+1); 448 } 449 snapshot.addRoot(new Root(id, to.threadId, 450 Root.JAVA_LOCAL, "", st)); 451 break; 452 } 453 case HPROF_GC_ROOT_NATIVE_STACK: { 454 long id = readID(); 455 int threadSeq = in.readInt(); 456 bytesLeft -= identifierSize + 4; 457 ThreadObject to = getThreadObjectFromSequence(threadSeq); 458 StackTrace st = getStackTraceFromSerial(to.stackSeq); 459 snapshot.addRoot(new Root(id, to.threadId, 460 Root.NATIVE_STACK, "", st)); 461 break; 462 } 463 case HPROF_GC_ROOT_STICKY_CLASS: { 464 long id = readID(); 465 bytesLeft -= identifierSize; 466 snapshot.addRoot(new Root(id, 0, Root.SYSTEM_CLASS, "")); 467 break; 468 } 469 case HPROF_GC_ROOT_THREAD_BLOCK: { 470 long id = readID(); 471 int threadSeq = in.readInt(); 472 bytesLeft -= identifierSize + 4; 473 ThreadObject to = getThreadObjectFromSequence(threadSeq); 474 StackTrace st = getStackTraceFromSerial(to.stackSeq); 475 snapshot.addRoot(new Root(id, to.threadId, 476 Root.THREAD_BLOCK, "", st)); 477 break; 478 } 479 case HPROF_GC_ROOT_MONITOR_USED: { 480 long id = readID(); 481 bytesLeft -= identifierSize; 482 snapshot.addRoot(new Root(id, 0, Root.BUSY_MONITOR, "")); 483 break; 484 } 485 case HPROF_GC_CLASS_DUMP: { 486 int bytesRead = readClass(); 487 bytesLeft -= bytesRead; 488 break; 489 } 490 case HPROF_GC_INSTANCE_DUMP: { 491 int bytesRead = readInstance(); 492 bytesLeft -= bytesRead; 493 break; 494 } 495 case HPROF_GC_OBJ_ARRAY_DUMP: { 496 long bytesRead = readArray(false); 497 bytesLeft -= bytesRead; 498 break; 499 } 500 case HPROF_GC_PRIM_ARRAY_DUMP: { 501 long bytesRead = readArray(true); 502 bytesLeft -= bytesRead; 503 break; 504 } 505 default: { 506 throw new IOException("Unrecognized heap dump sub-record type: " + type); 507 } 508 } 509 } 510 if (bytesLeft != 0) { 511 warn("Error reading heap dump or heap dump segment: Byte count is " + bytesLeft + " instead of 0"); 512 skipBytes(bytesLeft); 513 } 514 if (debugLevel > 0) { 515 System.out.println(" Finished heap sub-records."); 516 } 517 } 518 519 private long readID() throws IOException { 520 return (identifierSize == 4)? 521 (Snapshot.SMALL_ID_MASK & (long)in.readInt()) : in.readLong(); 522 } 523 524 // 525 // Read a java value. If result is non-null, it's expected to be an 526 // array of one element. We use it to fake multiple return values. 527 // @returns the number of bytes read 528 // 529 private int readValue(JavaThing[] resultArr) throws IOException { 530 byte type = in.readByte(); 531 return 1 + readValueForType(type, resultArr); 532 } 533 534 private int readValueForType(byte type, JavaThing[] resultArr) 535 throws IOException { 536 if (version >= VERSION_JDK12BETA4) { 537 type = signatureFromTypeId(type); 538 } 539 return readValueForTypeSignature(type, resultArr); 540 } 541 542 private int readValueForTypeSignature(byte type, JavaThing[] resultArr) 543 throws IOException { 544 switch (type) { 545 case '[': 546 case 'L': { 547 long id = readID(); 548 if (resultArr != null) { 549 resultArr[0] = new JavaObjectRef(id); 550 } 551 return identifierSize; 552 } 553 case 'Z': { 554 int b = in.readByte(); 555 if (b != 0 && b != 1) { 556 warn("Illegal boolean value read"); 557 } 558 if (resultArr != null) { 559 resultArr[0] = new JavaBoolean(b != 0); 560 } 561 return 1; 562 } 563 case 'B': { 564 byte b = in.readByte(); 565 if (resultArr != null) { 566 resultArr[0] = new JavaByte(b); 567 } 568 return 1; 569 } 570 case 'S': { 571 short s = in.readShort(); 572 if (resultArr != null) { 573 resultArr[0] = new JavaShort(s); 574 } 575 return 2; 576 } 577 case 'C': { 578 char ch = in.readChar(); 579 if (resultArr != null) { 580 resultArr[0] = new JavaChar(ch); 581 } 582 return 2; 583 } 584 case 'I': { 585 int val = in.readInt(); 586 if (resultArr != null) { 587 resultArr[0] = new JavaInt(val); 588 } 589 return 4; 590 } 591 case 'J': { 592 long val = in.readLong(); 593 if (resultArr != null) { 594 resultArr[0] = new JavaLong(val); 595 } 596 return 8; 597 } 598 case 'F': { 599 float val = in.readFloat(); 600 if (resultArr != null) { 601 resultArr[0] = new JavaFloat(val); 602 } 603 return 4; 604 } 605 case 'D': { 606 double val = in.readDouble(); 607 if (resultArr != null) { 608 resultArr[0] = new JavaDouble(val); 609 } 610 return 8; 611 } 612 default: { 613 throw new IOException("Bad value signature: " + type); 614 } 615 } 616 } 617 618 private ThreadObject getThreadObjectFromSequence(int threadSeq) 619 throws IOException { 620 ThreadObject to = threadObjects.get(threadSeq); 621 if (to == null) { 622 throw new IOException("Thread " + threadSeq + 623 " not found for JNI local ref"); 624 } 625 return to; 626 } 627 628 private String getNameFromID(long id) throws IOException { 629 return getNameFromID(Long.valueOf(id)); 630 } 631 632 private String getNameFromID(Long id) throws IOException { 633 if (id.longValue() == 0L) { 634 return ""; 635 } 636 String result = names.get(id); 637 if (result == null) { 638 warn("Name not found at " + toHex(id.longValue())); 639 return "unresolved name " + toHex(id.longValue()); 640 } 641 return result; 642 } 643 644 private StackTrace getStackTraceFromSerial(int ser) throws IOException { 645 if (stackTraces == null) { 646 return null; 647 } 648 StackTrace result = stackTraces.get(ser); 649 if (result == null) { 650 warn("Stack trace not found for serial # " + ser); 651 } 652 return result; 653 } 654 655 // 656 // Handle a HPROF_GC_CLASS_DUMP 657 // Return number of bytes read 658 // 659 private int readClass() throws IOException { 660 long id = readID(); 661 StackTrace stackTrace = getStackTraceFromSerial(in.readInt()); 662 long superId = readID(); 663 long classLoaderId = readID(); 664 long signersId = readID(); 665 long protDomainId = readID(); 666 long reserved1 = readID(); 667 long reserved2 = readID(); 668 int instanceSize = in.readInt(); 669 int bytesRead = 7 * identifierSize + 8; 670 671 int numConstPoolEntries = in.readUnsignedShort(); 672 bytesRead += 2; 673 for (int i = 0; i < numConstPoolEntries; i++) { 674 int index = in.readUnsignedShort(); // unused 675 bytesRead += 2; 676 bytesRead += readValue(null); // We ignore the values 677 } 678 679 int numStatics = in.readUnsignedShort(); 680 bytesRead += 2; 681 JavaThing[] valueBin = new JavaThing[1]; 682 JavaStatic[] statics = new JavaStatic[numStatics]; 683 for (int i = 0; i < numStatics; i++) { 684 long nameId = readID(); 685 bytesRead += identifierSize; 686 byte type = in.readByte(); 687 bytesRead++; 688 bytesRead += readValueForType(type, valueBin); 689 String fieldName = getNameFromID(nameId); 690 if (version >= VERSION_JDK12BETA4) { 691 type = signatureFromTypeId(type); 692 } 693 String signature = "" + ((char) type); 694 JavaField f = new JavaField(fieldName, signature); 695 statics[i] = new JavaStatic(f, valueBin[0]); 696 } 697 698 int numFields = in.readUnsignedShort(); 699 bytesRead += 2; 700 JavaField[] fields = new JavaField[numFields]; 701 for (int i = 0; i < numFields; i++) { 702 long nameId = readID(); 703 bytesRead += identifierSize; 704 byte type = in.readByte(); 705 bytesRead++; 706 String fieldName = getNameFromID(nameId); 707 if (version >= VERSION_JDK12BETA4) { 708 type = signatureFromTypeId(type); 709 } 710 String signature = "" + ((char) type); 711 fields[i] = new JavaField(fieldName, signature); 712 } 713 String name = classNameFromObjectID.get(id); 714 if (name == null) { 715 warn("Class name not found for " + toHex(id)); 716 name = "unknown-name@" + toHex(id); 717 } 718 JavaClass c = new JavaClass(id, name, superId, classLoaderId, signersId, 719 protDomainId, fields, statics, 720 instanceSize); 721 snapshot.addClass(id, c); 722 snapshot.setSiteTrace(c, stackTrace); 723 724 return bytesRead; 725 } 726 727 private String toHex(long addr) { 728 return jdk.test.lib.hprof.util.Misc.toHex(addr); 729 } 730 731 // 732 // Handle a HPROF_GC_INSTANCE_DUMP 733 // Return number of bytes read 734 // 735 private int readInstance() throws IOException { 736 long start = in.position(); 737 long id = readID(); 738 StackTrace stackTrace = getStackTraceFromSerial(in.readInt()); 739 long classID = readID(); 740 int bytesFollowing = in.readInt(); 741 int bytesRead = (2 * identifierSize) + 8 + bytesFollowing; 742 JavaObject jobj = new JavaObject(classID, start); 743 skipBytes(bytesFollowing); 744 snapshot.addHeapObject(id, jobj); 745 snapshot.setSiteTrace(jobj, stackTrace); 746 return bytesRead; 747 } 748 749 // 750 // Handle a HPROF_GC_OBJ_ARRAY_DUMP or HPROF_GC_PRIM_ARRAY_DUMP 751 // Return number of bytes read 752 // 753 private long readArray(boolean isPrimitive) throws IOException { 754 long start = in.position(); 755 long id = readID(); 756 StackTrace stackTrace = getStackTraceFromSerial(in.readInt()); 757 int num = in.readInt(); 758 long bytesRead = identifierSize + 8; 759 long elementClassID; 760 if (isPrimitive) { 761 elementClassID = in.readByte(); 762 bytesRead++; 763 } else { 764 elementClassID = readID(); 765 bytesRead += identifierSize; 766 } 767 768 // Check for primitive arrays: 769 byte primitiveSignature = 0x00; 770 int elSize = 0; 771 if (isPrimitive || version < VERSION_JDK12BETA4) { 772 switch ((int)elementClassID) { 773 case T_BOOLEAN: { 774 primitiveSignature = (byte) 'Z'; 775 elSize = 1; 776 break; 777 } 778 case T_CHAR: { 779 primitiveSignature = (byte) 'C'; 780 elSize = 2; 781 break; 782 } 783 case T_FLOAT: { 784 primitiveSignature = (byte) 'F'; 785 elSize = 4; 786 break; 787 } 788 case T_DOUBLE: { 789 primitiveSignature = (byte) 'D'; 790 elSize = 8; 791 break; 792 } 793 case T_BYTE: { 794 primitiveSignature = (byte) 'B'; 795 elSize = 1; 796 break; 797 } 798 case T_SHORT: { 799 primitiveSignature = (byte) 'S'; 800 elSize = 2; 801 break; 802 } 803 case T_INT: { 804 primitiveSignature = (byte) 'I'; 805 elSize = 4; 806 break; 807 } 808 case T_LONG: { 809 primitiveSignature = (byte) 'J'; 810 elSize = 8; 811 break; 812 } 813 } 814 if (version >= VERSION_JDK12BETA4 && primitiveSignature == 0x00) { 815 throw new IOException("Unrecognized typecode: " 816 + elementClassID); 817 } 818 } 819 if (primitiveSignature != 0x00) { 820 long size = elSize * (long)num; 821 bytesRead += size; 822 JavaValueArray va = new JavaValueArray(primitiveSignature, start); 823 skipBytes(size); 824 snapshot.addHeapObject(id, va); 825 snapshot.setSiteTrace(va, stackTrace); 826 } else { 827 long sz = (long)num * identifierSize; 828 bytesRead += sz; 829 JavaObjectArray arr = new JavaObjectArray(elementClassID, start); 830 skipBytes(sz); 831 snapshot.addHeapObject(id, arr); 832 snapshot.setSiteTrace(arr, stackTrace); 833 } 834 return bytesRead; 835 } 836 837 private byte signatureFromTypeId(byte typeId) throws IOException { 838 switch (typeId) { 839 case T_CLASS: { 840 return (byte) 'L'; 841 } 842 case T_BOOLEAN: { 843 return (byte) 'Z'; 844 } 845 case T_CHAR: { 846 return (byte) 'C'; 847 } 848 case T_FLOAT: { 849 return (byte) 'F'; 850 } 851 case T_DOUBLE: { 852 return (byte) 'D'; 853 } 854 case T_BYTE: { 855 return (byte) 'B'; 856 } 857 case T_SHORT: { 858 return (byte) 'S'; 859 } 860 case T_INT: { 861 return (byte) 'I'; 862 } 863 case T_LONG: { 864 return (byte) 'J'; 865 } 866 default: { 867 throw new IOException("Invalid type id of " + typeId); 868 } 869 } 870 } 871 872 private void handleEOF(EOFException exp, Snapshot snapshot) { 873 if (debugLevel > 0) { 874 exp.printStackTrace(); 875 } 876 warn("Unexpected EOF. Will miss information..."); 877 // we have EOF, we have to tolerate missing references 878 snapshot.setUnresolvedObjectsOK(true); 879 } 880 881 private void warn(String msg) { 882 System.out.println("WARNING: " + msg); 883 } 884 885 // 886 // A trivial data-holder class for HPROF_GC_ROOT_THREAD_OBJ. 887 // 888 private class ThreadObject { 889 890 long threadId; 891 int stackSeq; 892 893 ThreadObject(long threadId, int stackSeq) { 894 this.threadId = threadId; 895 this.stackSeq = stackSeq; 896 } 897 } 898 899} 900