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+
33+package com.sun.tools.hat.internal.parser;
34+
35+import java.io.*;
36+import java.util.Date;
37+import java.util.Hashtable;
38+import com.sun.tools.hat.internal.model.ArrayTypeCodes;
39+import 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+
47+public 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+}