History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/com/sun/tools/hat/internal/parser/HprofReader.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/tools/hat/internal/parser/HprofReader.java+892−0
@@ -0,0 +1,892 @@
1/*
2 * Copyright (c) 1997, 2008, 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 com.sun.tools.hat.internal.parser;
34
35import java.io.*;
36import java.util.Date;
37import java.util.Hashtable;
38import com.sun.tools.hat.internal.model.ArrayTypeCodes;
39import com.sun.tools.hat.internal.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(new Long(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 = new Long(classID);
227 String nm = getNameFromID(classNameID).replace('/', '.');
228 classNameFromObjectID.put(classIdI, nm);
229 if (classNameFromSerialNo != null) {
230 classNameFromSerialNo.put(new Integer(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(new Integer(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(new Long(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(new Long(fid));
323 if (frames[i] == null) {
324 throw new IOException("Stack frame " + toHex(fid) + " not found");
325 }
326 }
327 stackTraces.put(new Integer(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 in.skipBytes((int)length);
358 }
359
360 private int readVersionHeader() throws IOException {
361 int candidatesLeft = VERSIONS.length;
362 boolean[] matched = new boolean[VERSIONS.length];
363 for (int i = 0; i < candidatesLeft; i++) {
364 matched[i] = true;
365 }
366
367 int pos = 0;
368 while (candidatesLeft > 0) {
369 char c = (char) in.readByte();
370 currPos++;
371 for (int i = 0; i < VERSIONS.length; i++) {
372 if (matched[i]) {
373 if (c != VERSIONS[i].charAt(pos)) { // Not matched
374 matched[i] = false;
375 --candidatesLeft;
376 } else if (pos == VERSIONS[i].length() - 1) { // Full match
377 return i;
378 }
379 }
380 }
381 ++pos;
382 }
383 throw new IOException("Version string not recognized at byte " + (pos+3));
384 }
385
386 private void readHeapDump(long bytesLeft, long posAtEnd) throws IOException {
387 while (bytesLeft > 0) {
388 int type = in.readUnsignedByte();
389 if (debugLevel > 0) {
390 System.out.println(" Read heap sub-record type " + type
391 + " at position "
392 + toHex(posAtEnd - bytesLeft));
393 }
394 bytesLeft--;
395 switch(type) {
396 case HPROF_GC_ROOT_UNKNOWN: {
397 long id = readID();
398 bytesLeft -= identifierSize;
399 snapshot.addRoot(new Root(id, 0, Root.UNKNOWN, ""));
400 break;
401 }
402 case HPROF_GC_ROOT_THREAD_OBJ: {
403 long id = readID();
404 int threadSeq = in.readInt();
405 int stackSeq = in.readInt();
406 bytesLeft -= identifierSize + 8;
407 threadObjects.put(new Integer(threadSeq),
408 new ThreadObject(id, stackSeq));
409 break;
410 }
411 case HPROF_GC_ROOT_JNI_GLOBAL: {
412 long id = readID();
413 long globalRefId = readID(); // Ignored, for now
414 bytesLeft -= 2*identifierSize;
415 snapshot.addRoot(new Root(id, 0, Root.NATIVE_STATIC, ""));
416 break;
417 }
418 case HPROF_GC_ROOT_JNI_LOCAL: {
419 long id = readID();
420 int threadSeq = in.readInt();
421 int depth = in.readInt();
422 bytesLeft -= identifierSize + 8;
423 ThreadObject to = getThreadObjectFromSequence(threadSeq);
424 StackTrace st = getStackTraceFromSerial(to.stackSeq);
425 if (st != null) {
426 st = st.traceForDepth(depth+1);
427 }
428 snapshot.addRoot(new Root(id, to.threadId,
429 Root.NATIVE_LOCAL, "", st));
430 break;
431 }
432 case HPROF_GC_ROOT_JAVA_FRAME: {
433 long id = readID();
434 int threadSeq = in.readInt();
435 int depth = in.readInt();
436 bytesLeft -= identifierSize + 8;
437 ThreadObject to = getThreadObjectFromSequence(threadSeq);
438 StackTrace st = getStackTraceFromSerial(to.stackSeq);
439 if (st != null) {
440 st = st.traceForDepth(depth+1);
441 }
442 snapshot.addRoot(new Root(id, to.threadId,
443 Root.JAVA_LOCAL, "", st));
444 break;
445 }
446 case HPROF_GC_ROOT_NATIVE_STACK: {
447 long id = readID();
448 int threadSeq = in.readInt();
449 bytesLeft -= identifierSize + 4;
450 ThreadObject to = getThreadObjectFromSequence(threadSeq);
451 StackTrace st = getStackTraceFromSerial(to.stackSeq);
452 snapshot.addRoot(new Root(id, to.threadId,
453 Root.NATIVE_STACK, "", st));
454 break;
455 }
456 case HPROF_GC_ROOT_STICKY_CLASS: {
457 long id = readID();
458 bytesLeft -= identifierSize;
459 snapshot.addRoot(new Root(id, 0, Root.SYSTEM_CLASS, ""));
460 break;
461 }
462 case HPROF_GC_ROOT_THREAD_BLOCK: {
463 long id = readID();
464 int threadSeq = in.readInt();
465 bytesLeft -= identifierSize + 4;
466 ThreadObject to = getThreadObjectFromSequence(threadSeq);
467 StackTrace st = getStackTraceFromSerial(to.stackSeq);
468 snapshot.addRoot(new Root(id, to.threadId,
469 Root.THREAD_BLOCK, "", st));
470 break;
471 }
472 case HPROF_GC_ROOT_MONITOR_USED: {
473 long id = readID();
474 bytesLeft -= identifierSize;
475 snapshot.addRoot(new Root(id, 0, Root.BUSY_MONITOR, ""));
476 break;
477 }
478 case HPROF_GC_CLASS_DUMP: {
479 int bytesRead = readClass();
480 bytesLeft -= bytesRead;
481 break;
482 }
483 case HPROF_GC_INSTANCE_DUMP: {
484 int bytesRead = readInstance();
485 bytesLeft -= bytesRead;
486 break;
487 }
488 case HPROF_GC_OBJ_ARRAY_DUMP: {
489 int bytesRead = readArray(false);
490 bytesLeft -= bytesRead;
491 break;
492 }
493 case HPROF_GC_PRIM_ARRAY_DUMP: {
494 int bytesRead = readArray(true);
495 bytesLeft -= bytesRead;
496 break;
497 }
498 default: {
499 throw new IOException("Unrecognized heap dump sub-record type: " + type);
500 }
501 }
502 }
503 if (bytesLeft != 0) {
504 warn("Error reading heap dump or heap dump segment: Byte count is " + bytesLeft + " instead of 0");
505 skipBytes(bytesLeft);
506 }
507 if (debugLevel > 0) {
508 System.out.println(" Finished heap sub-records.");
509 }
510 }
511
512 private long readID() throws IOException {
513 return (identifierSize == 4)?
514 (Snapshot.SMALL_ID_MASK & (long)in.readInt()) : in.readLong();
515 }
516
517 //
518 // Read a java value. If result is non-null, it's expected to be an
519 // array of one element. We use it to fake multiple return values.
520 // @returns the number of bytes read
521 //
522 private int readValue(JavaThing[] resultArr) throws IOException {
523 byte type = in.readByte();
524 return 1 + readValueForType(type, resultArr);
525 }
526
527 private int readValueForType(byte type, JavaThing[] resultArr)
528 throws IOException {
529 if (version >= VERSION_JDK12BETA4) {
530 type = signatureFromTypeId(type);
531 }
532 return readValueForTypeSignature(type, resultArr);
533 }
534
535 private int readValueForTypeSignature(byte type, JavaThing[] resultArr)
536 throws IOException {
537 switch (type) {
538 case '[':
539 case 'L': {
540 long id = readID();
541 if (resultArr != null) {
542 resultArr[0] = new JavaObjectRef(id);
543 }
544 return identifierSize;
545 }
546 case 'Z': {
547 int b = in.readByte();
548 if (b != 0 && b != 1) {
549 warn("Illegal boolean value read");
550 }
551 if (resultArr != null) {
552 resultArr[0] = new JavaBoolean(b != 0);
553 }
554 return 1;
555 }
556 case 'B': {
557 byte b = in.readByte();
558 if (resultArr != null) {
559 resultArr[0] = new JavaByte(b);
560 }
561 return 1;
562 }
563 case 'S': {
564 short s = in.readShort();
565 if (resultArr != null) {
566 resultArr[0] = new JavaShort(s);
567 }
568 return 2;
569 }
570 case 'C': {
571 char ch = in.readChar();
572 if (resultArr != null) {
573 resultArr[0] = new JavaChar(ch);
574 }
575 return 2;
576 }
577 case 'I': {
578 int val = in.readInt();
579 if (resultArr != null) {
580 resultArr[0] = new JavaInt(val);
581 }
582 return 4;
583 }
584 case 'J': {
585 long val = in.readLong();
586 if (resultArr != null) {
587 resultArr[0] = new JavaLong(val);
588 }
589 return 8;
590 }
591 case 'F': {
592 float val = in.readFloat();
593 if (resultArr != null) {
594 resultArr[0] = new JavaFloat(val);
595 }
596 return 4;
597 }
598 case 'D': {
599 double val = in.readDouble();
600 if (resultArr != null) {
601 resultArr[0] = new JavaDouble(val);
602 }
603 return 8;
604 }
605 default: {
606 throw new IOException("Bad value signature: " + type);
607 }
608 }
609 }
610
611 private ThreadObject getThreadObjectFromSequence(int threadSeq)
612 throws IOException {
613 ThreadObject to = threadObjects.get(new Integer(threadSeq));
614 if (to == null) {
615 throw new IOException("Thread " + threadSeq +
616 " not found for JNI local ref");
617 }
618 return to;
619 }
620
621 private String getNameFromID(long id) throws IOException {
622 return getNameFromID(new Long(id));
623 }
624
625 private String getNameFromID(Long id) throws IOException {
626 if (id.longValue() == 0L) {
627 return "";
628 }
629 String result = names.get(id);
630 if (result == null) {
631 warn("Name not found at " + toHex(id.longValue()));
632 return "unresolved name " + toHex(id.longValue());
633 }
634 return result;
635 }
636
637 private StackTrace getStackTraceFromSerial(int ser) throws IOException {
638 if (stackTraces == null) {
639 return null;
640 }
641 StackTrace result = stackTraces.get(new Integer(ser));
642 if (result == null) {
643 warn("Stack trace not found for serial # " + ser);
644 }
645 return result;
646 }
647
648 //
649 // Handle a HPROF_GC_CLASS_DUMP
650 // Return number of bytes read
651 //
652 private int readClass() throws IOException {
653 long id = readID();
654 StackTrace stackTrace = getStackTraceFromSerial(in.readInt());
655 long superId = readID();
656 long classLoaderId = readID();
657 long signersId = readID();
658 long protDomainId = readID();
659 long reserved1 = readID();
660 long reserved2 = readID();
661 int instanceSize = in.readInt();
662 int bytesRead = 7 * identifierSize + 8;
663
664 int numConstPoolEntries = in.readUnsignedShort();
665 bytesRead += 2;
666 for (int i = 0; i < numConstPoolEntries; i++) {
667 int index = in.readUnsignedShort(); // unused
668 bytesRead += 2;
669 bytesRead += readValue(null); // We ignore the values
670 }
671
672 int numStatics = in.readUnsignedShort();
673 bytesRead += 2;
674 JavaThing[] valueBin = new JavaThing[1];
675 JavaStatic[] statics = new JavaStatic[numStatics];
676 for (int i = 0; i < numStatics; i++) {
677 long nameId = readID();
678 bytesRead += identifierSize;
679 byte type = in.readByte();
680 bytesRead++;
681 bytesRead += readValueForType(type, valueBin);
682 String fieldName = getNameFromID(nameId);
683 if (version >= VERSION_JDK12BETA4) {
684 type = signatureFromTypeId(type);
685 }
686 String signature = "" + ((char) type);
687 JavaField f = new JavaField(fieldName, signature);
688 statics[i] = new JavaStatic(f, valueBin[0]);
689 }
690
691 int numFields = in.readUnsignedShort();
692 bytesRead += 2;
693 JavaField[] fields = new JavaField[numFields];
694 for (int i = 0; i < numFields; i++) {
695 long nameId = readID();
696 bytesRead += identifierSize;
697 byte type = in.readByte();
698 bytesRead++;
699 String fieldName = getNameFromID(nameId);
700 if (version >= VERSION_JDK12BETA4) {
701 type = signatureFromTypeId(type);
702 }
703 String signature = "" + ((char) type);
704 fields[i] = new JavaField(fieldName, signature);
705 }
706 String name = classNameFromObjectID.get(new Long(id));
707 if (name == null) {
708 warn("Class name not found for " + toHex(id));
709 name = "unknown-name@" + toHex(id);
710 }
711 JavaClass c = new JavaClass(id, name, superId, classLoaderId, signersId,
712 protDomainId, fields, statics,
713 instanceSize);
714 snapshot.addClass(id, c);
715 snapshot.setSiteTrace(c, stackTrace);
716
717 return bytesRead;
718 }
719
720 private String toHex(long addr) {
721 return com.sun.tools.hat.internal.util.Misc.toHex(addr);
722 }
723
724 //
725 // Handle a HPROF_GC_INSTANCE_DUMP
726 // Return number of bytes read
727 //
728 private int readInstance() throws IOException {
729 long start = in.position();
730 long id = readID();
731 StackTrace stackTrace = getStackTraceFromSerial(in.readInt());
732 long classID = readID();
733 int bytesFollowing = in.readInt();
734 int bytesRead = (2 * identifierSize) + 8 + bytesFollowing;
735 JavaObject jobj = new JavaObject(classID, start);
736 skipBytes(bytesFollowing);
737 snapshot.addHeapObject(id, jobj);
738 snapshot.setSiteTrace(jobj, stackTrace);
739 return bytesRead;
740 }
741
742 //
743 // Handle a HPROF_GC_OBJ_ARRAY_DUMP or HPROF_GC_PRIM_ARRAY_DUMP
744 // Return number of bytes read
745 //
746 private int readArray(boolean isPrimitive) throws IOException {
747 long start = in.position();
748 long id = readID();
749 StackTrace stackTrace = getStackTraceFromSerial(in.readInt());
750 int num = in.readInt();
751 int bytesRead = identifierSize + 8;
752 long elementClassID;
753 if (isPrimitive) {
754 elementClassID = in.readByte();
755 bytesRead++;
756 } else {
757 elementClassID = readID();
758 bytesRead += identifierSize;
759 }
760
761 // Check for primitive arrays:
762 byte primitiveSignature = 0x00;
763 int elSize = 0;
764 if (isPrimitive || version < VERSION_JDK12BETA4) {
765 switch ((int)elementClassID) {
766 case T_BOOLEAN: {
767 primitiveSignature = (byte) 'Z';
768 elSize = 1;
769 break;
770 }
771 case T_CHAR: {
772 primitiveSignature = (byte) 'C';
773 elSize = 2;
774 break;
775 }
776 case T_FLOAT: {
777 primitiveSignature = (byte) 'F';
778 elSize = 4;
779 break;
780 }
781 case T_DOUBLE: {
782 primitiveSignature = (byte) 'D';
783 elSize = 8;
784 break;
785 }
786 case T_BYTE: {
787 primitiveSignature = (byte) 'B';
788 elSize = 1;
789 break;
790 }
791 case T_SHORT: {
792 primitiveSignature = (byte) 'S';
793 elSize = 2;
794 break;
795 }
796 case T_INT: {
797 primitiveSignature = (byte) 'I';
798 elSize = 4;
799 break;
800 }
801 case T_LONG: {
802 primitiveSignature = (byte) 'J';
803 elSize = 8;
804 break;
805 }
806 }
807 if (version >= VERSION_JDK12BETA4 && primitiveSignature == 0x00) {
808 throw new IOException("Unrecognized typecode: "
809 + elementClassID);
810 }
811 }
812 if (primitiveSignature != 0x00) {
813 int size = elSize * num;
814 bytesRead += size;
815 JavaValueArray va = new JavaValueArray(primitiveSignature, start);
816 skipBytes(size);
817 snapshot.addHeapObject(id, va);
818 snapshot.setSiteTrace(va, stackTrace);
819 } else {
820 int sz = num * identifierSize;
821 bytesRead += sz;
822 JavaObjectArray arr = new JavaObjectArray(elementClassID, start);
823 skipBytes(sz);
824 snapshot.addHeapObject(id, arr);
825 snapshot.setSiteTrace(arr, stackTrace);
826 }
827 return bytesRead;
828 }
829
830 private byte signatureFromTypeId(byte typeId) throws IOException {
831 switch (typeId) {
832 case T_CLASS: {
833 return (byte) 'L';
834 }
835 case T_BOOLEAN: {
836 return (byte) 'Z';
837 }
838 case T_CHAR: {
839 return (byte) 'C';
840 }
841 case T_FLOAT: {
842 return (byte) 'F';
843 }
844 case T_DOUBLE: {
845 return (byte) 'D';
846 }
847 case T_BYTE: {
848 return (byte) 'B';
849 }
850 case T_SHORT: {
851 return (byte) 'S';
852 }
853 case T_INT: {
854 return (byte) 'I';
855 }
856 case T_LONG: {
857 return (byte) 'J';
858 }
859 default: {
860 throw new IOException("Invalid type id of " + typeId);
861 }
862 }
863 }
864
865 private void handleEOF(EOFException exp, Snapshot snapshot) {
866 if (debugLevel > 0) {
867 exp.printStackTrace();
868 }
869 warn("Unexpected EOF. Will miss information...");
870 // we have EOF, we have to tolerate missing references
871 snapshot.setUnresolvedObjectsOK(true);
872 }
873
874 private void warn(String msg) {
875 System.out.println("WARNING: " + msg);
876 }
877
878 //
879 // A trivial data-holder class for HPROF_GC_ROOT_THREAD_OBJ.
880 //
881 private class ThreadObject {
882
883 long threadId;
884 int stackSeq;
885
886 ThreadObject(long threadId, int stackSeq) {
887 this.threadId = threadId;
888 this.stackSeq = stackSeq;
889 }
890 }
891
892}