1 /*
2  * Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  *
23  */
24 
25 package sun.jvm.hotspot.utilities;
26 
27 import java.io.*;
28 import java.nio.channels.*;
29 import java.util.*;
30 import sun.jvm.hotspot.debugger.*;
31 import sun.jvm.hotspot.memory.*;
32 import sun.jvm.hotspot.oops.*;
33 import sun.jvm.hotspot.runtime.*;
34 import sun.jvm.hotspot.classfile.*;
35 import sun.jvm.hotspot.gc.z.ZCollectedHeap;
36 
37 /*
38  * This class writes Java heap in hprof binary format. This format is
39  * used by Heap Analysis Tool (HAT). The class is heavily influenced
40  * by 'hprof_io.c' of 1.5 new hprof implementation.
41  */
42 
43 /* hprof binary format: (result either written to a file or sent over
44  * the network).
45  *
46  * WARNING: This format is still under development, and is subject to
47  * change without notice.
48  *
49  * header     "JAVA PROFILE 1.0.2" (0-terminated)
50  * u4         size of identifiers. Identifiers are used to represent
51  *            UTF8 strings, objects, stack traces, etc. They usually
52  *            have the same size as host pointers. For example, on
53  *            Solaris and Win32, the size is 4.
54  * u4         high word
55  * u4         low word    number of milliseconds since 0:00 GMT, 1/1/70
56  * [record]*  a sequence of records.
57  *
58  */
59 
60 /*
61  *
62  * Record format:
63  *
64  * u1         a TAG denoting the type of the record
65  * u4         number of *microseconds* since the time stamp in the
66  *            header. (wraps around in a little more than an hour)
67  * u4         number of bytes *remaining* in the record. Note that
68  *            this number excludes the tag and the length field itself.
69  * [u1]*      BODY of the record (a sequence of bytes)
70  */
71 
72 /*
73  * The following TAGs are supported:
74  *
75  * TAG           BODY       notes
76  *----------------------------------------------------------
77  * HPROF_UTF8               a UTF8-encoded name
78  *
79  *               id         name ID
80  *               [u1]*      UTF8 characters (no trailing zero)
81  *
82  * HPROF_LOAD_CLASS         a newly loaded class
83  *
84  *                u4        class serial number (> 0)
85  *                id        class object ID
86  *                u4        stack trace serial number
87  *                id        class name ID
88  *
89  * HPROF_UNLOAD_CLASS       an unloading class
90  *
91  *                u4        class serial_number
92  *
93  * HPROF_FRAME              a Java stack frame
94  *
95  *                id        stack frame ID
96  *                id        method name ID
97  *                id        method signature ID
98  *                id        source file name ID
99  *                u4        class serial number
100  *                i4        line number. >0: normal
101  *                                       -1: unknown
102  *                                       -2: compiled method
103  *                                       -3: native method
104  *
105  * HPROF_TRACE              a Java stack trace
106  *
107  *               u4         stack trace serial number
108  *               u4         thread serial number
109  *               u4         number of frames
110  *               [id]*      stack frame IDs
111  *
112  *
113  * HPROF_ALLOC_SITES        a set of heap allocation sites, obtained after GC
114  *
115  *               u2         flags 0x0001: incremental vs. complete
116  *                                0x0002: sorted by allocation vs. live
117  *                                0x0004: whether to force a GC
118  *               u4         cutoff ratio
119  *               u4         total live bytes
120  *               u4         total live instances
121  *               u8         total bytes allocated
122  *               u8         total instances allocated
123  *               u4         number of sites that follow
124  *               [u1        is_array: 0:  normal object
125  *                                    2:  object array
126  *                                    4:  boolean array
127  *                                    5:  char array
128  *                                    6:  float array
129  *                                    7:  double array
130  *                                    8:  byte array
131  *                                    9:  short array
132  *                                    10: int array
133  *                                    11: long array
134  *                u4        class serial number (may be zero during startup)
135  *                u4        stack trace serial number
136  *                u4        number of bytes alive
137  *                u4        number of instances alive
138  *                u4        number of bytes allocated
139  *                u4]*      number of instance allocated
140  *
141  * HPROF_START_THREAD       a newly started thread.
142  *
143  *               u4         thread serial number (> 0)
144  *               id         thread object ID
145  *               u4         stack trace serial number
146  *               id         thread name ID
147  *               id         thread group name ID
148  *               id         thread group parent name ID
149  *
150  * HPROF_END_THREAD         a terminating thread.
151  *
152  *               u4         thread serial number
153  *
154  * HPROF_HEAP_SUMMARY       heap summary
155  *
156  *               u4         total live bytes
157  *               u4         total live instances
158  *               u8         total bytes allocated
159  *               u8         total instances allocated
160  *
161  * HPROF_HEAP_DUMP          denote a heap dump
162  *
163  *               [heap dump sub-records]*
164  *
165  *                          There are four kinds of heap dump sub-records:
166  *
167  *               u1         sub-record type
168  *
169  *               HPROF_GC_ROOT_UNKNOWN         unknown root
170  *
171  *                          id         object ID
172  *
173  *               HPROF_GC_ROOT_THREAD_OBJ      thread object
174  *
175  *                          id         thread object ID  (may be 0 for a
176  *                                     thread newly attached through JNI)
177  *                          u4         thread sequence number
178  *                          u4         stack trace sequence number
179  *
180  *               HPROF_GC_ROOT_JNI_GLOBAL      JNI global ref root
181  *
182  *                          id         object ID
183  *                          id         JNI global ref ID
184  *
185  *               HPROF_GC_ROOT_JNI_LOCAL       JNI local ref
186  *
187  *                          id         object ID
188  *                          u4         thread serial number
189  *                          u4         frame # in stack trace (-1 for empty)
190  *
191  *               HPROF_GC_ROOT_JAVA_FRAME      Java stack frame
192  *
193  *                          id         object ID
194  *                          u4         thread serial number
195  *                          u4         frame # in stack trace (-1 for empty)
196  *
197  *               HPROF_GC_ROOT_NATIVE_STACK    Native stack
198  *
199  *                          id         object ID
200  *                          u4         thread serial number
201  *
202  *               HPROF_GC_ROOT_STICKY_CLASS    System class
203  *
204  *                          id         object ID
205  *
206  *               HPROF_GC_ROOT_THREAD_BLOCK    Reference from thread block
207  *
208  *                          id         object ID
209  *                          u4         thread serial number
210  *
211  *               HPROF_GC_ROOT_MONITOR_USED    Busy monitor
212  *
213  *                          id         object ID
214  *
215  *               HPROF_GC_CLASS_DUMP           dump of a class object
216  *
217  *                          id         class object ID
218  *                          u4         stack trace serial number
219  *                          id         super class object ID
220  *                          id         class loader object ID
221  *                          id         signers object ID
222  *                          id         protection domain object ID
223  *                          id         reserved
224  *                          id         reserved
225  *
226  *                          u4         instance size (in bytes)
227  *
228  *                          u2         size of constant pool
229  *                          [u2,       constant pool index,
230  *                           ty,       type
231  *                                     2:  object
232  *                                     4:  boolean
233  *                                     5:  char
234  *                                     6:  float
235  *                                     7:  double
236  *                                     8:  byte
237  *                                     9:  short
238  *                                     10: int
239  *                                     11: long
240  *                           vl]*      and value
241  *
242  *                          u2         number of static fields
243  *                          [id,       static field name,
244  *                           ty,       type,
245  *                           vl]*      and value
246  *
247  *                          u2         number of inst. fields (not inc. super)
248  *                          [id,       instance field name,
249  *                           ty]*      type
250  *
251  *               HPROF_GC_INSTANCE_DUMP        dump of a normal object
252  *
253  *                          id         object ID
254  *                          u4         stack trace serial number
255  *                          id         class object ID
256  *                          u4         number of bytes that follow
257  *                          [vl]*      instance field values (class, followed
258  *                                     by super, super's super ...)
259  *
260  *               HPROF_GC_OBJ_ARRAY_DUMP       dump of an object array
261  *
262  *                          id         array object ID
263  *                          u4         stack trace serial number
264  *                          u4         number of elements
265  *                          id         array class ID
266  *                          [id]*      elements
267  *
268  *               HPROF_GC_PRIM_ARRAY_DUMP      dump of a primitive array
269  *
270  *                          id         array object ID
271  *                          u4         stack trace serial number
272  *                          u4         number of elements
273  *                          u1         element type
274  *                                     4:  boolean array
275  *                                     5:  char array
276  *                                     6:  float array
277  *                                     7:  double array
278  *                                     8:  byte array
279  *                                     9:  short array
280  *                                     10: int array
281  *                                     11: long array
282  *                          [u1]*      elements
283  *
284  * HPROF_CPU_SAMPLES        a set of sample traces of running threads
285  *
286  *                u4        total number of samples
287  *                u4        # of traces
288  *               [u4        # of samples
289  *                u4]*      stack trace serial number
290  *
291  * HPROF_CONTROL_SETTINGS   the settings of on/off switches
292  *
293  *                u4        0x00000001: alloc traces on/off
294  *                          0x00000002: cpu sampling on/off
295  *                u2        stack trace depth
296  *
297  *
298  * A heap dump can optionally be generated as a sequence of heap dump
299  * segments. This sequence is terminated by an end record. The additional
300  * tags allowed by format "JAVA PROFILE 1.0.2" are:
301  *
302  * HPROF_HEAP_DUMP_SEGMENT  denote a heap dump segment
303  *
304  *               [heap dump sub-records]*
305  *               The same sub-record types allowed by HPROF_HEAP_DUMP
306  *
307  * HPROF_HEAP_DUMP_END      denotes the end of a heap dump
308  *
309  */
310 
311 public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
312 
313     // Record which Symbol names have been dumped already.
314     private HashSet<Symbol> names;
315 
316     private static final long HPROF_SEGMENTED_HEAP_DUMP_THRESHOLD = 2L * 0x40000000;
317 
318     // The approximate size of a heap segment. Used to calculate when to create
319     // a new segment.
320     private static final long HPROF_SEGMENTED_HEAP_DUMP_SEGMENT_SIZE = 1L * 0x40000000;
321 
322     // hprof binary file header
323     private static final String HPROF_HEADER_1_0_2 = "JAVA PROFILE 1.0.2";
324 
325     // constants in enum HprofTag
326     private static final int HPROF_UTF8             = 0x01;
327     private static final int HPROF_LOAD_CLASS       = 0x02;
328     private static final int HPROF_UNLOAD_CLASS     = 0x03;
329     private static final int HPROF_FRAME            = 0x04;
330     private static final int HPROF_TRACE            = 0x05;
331     private static final int HPROF_ALLOC_SITES      = 0x06;
332     private static final int HPROF_HEAP_SUMMARY     = 0x07;
333     private static final int HPROF_START_THREAD     = 0x0A;
334     private static final int HPROF_END_THREAD       = 0x0B;
335     private static final int HPROF_HEAP_DUMP        = 0x0C;
336     private static final int HPROF_CPU_SAMPLES      = 0x0D;
337     private static final int HPROF_CONTROL_SETTINGS = 0x0E;
338 
339     // 1.0.2 record types
340     private static final int HPROF_HEAP_DUMP_SEGMENT = 0x1C;
341     private static final int HPROF_HEAP_DUMP_END     = 0x2C;
342 
343     // Heap dump constants
344     // constants in enum HprofGcTag
345     private static final int HPROF_GC_ROOT_UNKNOWN       = 0xFF;
346     private static final int HPROF_GC_ROOT_JNI_GLOBAL    = 0x01;
347     private static final int HPROF_GC_ROOT_JNI_LOCAL     = 0x02;
348     private static final int HPROF_GC_ROOT_JAVA_FRAME    = 0x03;
349     private static final int HPROF_GC_ROOT_NATIVE_STACK  = 0x04;
350     private static final int HPROF_GC_ROOT_STICKY_CLASS  = 0x05;
351     private static final int HPROF_GC_ROOT_THREAD_BLOCK  = 0x06;
352     private static final int HPROF_GC_ROOT_MONITOR_USED  = 0x07;
353     private static final int HPROF_GC_ROOT_THREAD_OBJ    = 0x08;
354     private static final int HPROF_GC_CLASS_DUMP         = 0x20;
355     private static final int HPROF_GC_INSTANCE_DUMP      = 0x21;
356     private static final int HPROF_GC_OBJ_ARRAY_DUMP     = 0x22;
357     private static final int HPROF_GC_PRIM_ARRAY_DUMP    = 0x23;
358 
359     // constants in enum HprofType
360     private static final int HPROF_ARRAY_OBJECT  = 1;
361     private static final int HPROF_NORMAL_OBJECT = 2;
362     private static final int HPROF_BOOLEAN       = 4;
363     private static final int HPROF_CHAR          = 5;
364     private static final int HPROF_FLOAT         = 6;
365     private static final int HPROF_DOUBLE        = 7;
366     private static final int HPROF_BYTE          = 8;
367     private static final int HPROF_SHORT         = 9;
368     private static final int HPROF_INT           = 10;
369     private static final int HPROF_LONG          = 11;
370 
371     // Java type codes
372     private static final int JVM_SIGNATURE_BOOLEAN = 'Z';
373     private static final int JVM_SIGNATURE_CHAR    = 'C';
374     private static final int JVM_SIGNATURE_BYTE    = 'B';
375     private static final int JVM_SIGNATURE_SHORT   = 'S';
376     private static final int JVM_SIGNATURE_INT     = 'I';
377     private static final int JVM_SIGNATURE_LONG    = 'J';
378     private static final int JVM_SIGNATURE_FLOAT   = 'F';
379     private static final int JVM_SIGNATURE_DOUBLE  = 'D';
380     private static final int JVM_SIGNATURE_ARRAY   = '[';
381     private static final int JVM_SIGNATURE_CLASS   = 'L';
382 
383     private static final long MAX_U4_VALUE = 0xFFFFFFFFL;
384     int serialNum = 1;
385 
HeapHprofBinWriter()386     public HeapHprofBinWriter() {
387         this.KlassMap = new ArrayList<Klass>();
388         this.names = new HashSet<Symbol>();
389     }
390 
write(String fileName)391     public synchronized void write(String fileName) throws IOException {
392         VM vm = VM.getVM();
393 
394         // open file stream and create buffered data output stream
395         fos = new FileOutputStream(fileName);
396         out = new DataOutputStream(new BufferedOutputStream(fos));
397 
398         dbg = vm.getDebugger();
399         objectHeap = vm.getObjectHeap();
400 
401         OBJ_ID_SIZE = (int) vm.getOopSize();
402 
403         BOOLEAN_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_BOOLEAN);
404         BYTE_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_BYTE);
405         CHAR_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_CHAR);
406         SHORT_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_SHORT);
407         INT_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_INT);
408         LONG_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_LONG);
409         FLOAT_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_FLOAT);
410         DOUBLE_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_DOUBLE);
411         OBJECT_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_OBJECT);
412 
413         BOOLEAN_SIZE = objectHeap.getBooleanSize();
414         BYTE_SIZE = objectHeap.getByteSize();
415         CHAR_SIZE = objectHeap.getCharSize();
416         SHORT_SIZE = objectHeap.getShortSize();
417         INT_SIZE = objectHeap.getIntSize();
418         LONG_SIZE = objectHeap.getLongSize();
419         FLOAT_SIZE = objectHeap.getFloatSize();
420         DOUBLE_SIZE = objectHeap.getDoubleSize();
421 
422         // Check weather we should dump the heap as segments
423         useSegmentedHeapDump = vm.getUniverse().heap().used() > HPROF_SEGMENTED_HEAP_DUMP_THRESHOLD;
424 
425         // hprof bin format header
426         writeFileHeader();
427 
428         // dummy stack trace without any frames so that
429         // HAT can be run without -stack false option
430         writeDummyTrace();
431 
432         // hprof UTF-8 symbols section
433         writeSymbols();
434 
435         // HPROF_LOAD_CLASS records for all classes
436         writeClasses();
437 
438         // write HPROF_FRAME and HPROF_TRACE records
439         dumpStackTraces();
440 
441         // write CLASS_DUMP records
442         writeClassDumpRecords();
443 
444         // this will write heap data into the buffer stream
445         super.write();
446 
447         // flush buffer stream.
448         out.flush();
449 
450         // Fill in final length
451         fillInHeapRecordLength();
452 
453         if (useSegmentedHeapDump) {
454             // Write heap segment-end record
455             out.writeByte((byte) HPROF_HEAP_DUMP_END);
456             out.writeInt(0);
457             out.writeInt(0);
458         }
459 
460         // flush buffer stream and throw it.
461         out.flush();
462         out = null;
463 
464         // close the file stream
465         fos.close();
466     }
467 
468     @Override
writeHeapRecordPrologue()469     protected void writeHeapRecordPrologue() throws IOException {
470         if (currentSegmentStart == 0) {
471             // write heap data header, depending on heap size use segmented heap
472             // format
473             out.writeByte((byte) (useSegmentedHeapDump ? HPROF_HEAP_DUMP_SEGMENT
474                     : HPROF_HEAP_DUMP));
475             out.writeInt(0);
476 
477             // remember position of dump length, we will fixup
478             // length later - hprof format requires length.
479             out.flush();
480             currentSegmentStart = fos.getChannel().position();
481             // write dummy length of 0 and we'll fix it later.
482             out.writeInt(0);
483         }
484     }
485 
486     @Override
writeHeapRecordEpilogue()487     protected void writeHeapRecordEpilogue() throws IOException {
488         if (useSegmentedHeapDump) {
489             out.flush();
490             if ((fos.getChannel().position() - currentSegmentStart - 4L) >= HPROF_SEGMENTED_HEAP_DUMP_SEGMENT_SIZE) {
491                 fillInHeapRecordLength();
492                 currentSegmentStart = 0;
493             }
494         }
495     }
496 
fillInHeapRecordLength()497     private void fillInHeapRecordLength() throws IOException {
498 
499         // now get the current position to calculate length
500         long dumpEnd = fos.getChannel().position();
501 
502         // calculate the length of heap data
503         long dumpLenLong = (dumpEnd - currentSegmentStart - 4L);
504 
505         // Check length boundary, overflow could happen but is _very_ unlikely
506         if (dumpLenLong >= (4L * 0x40000000)) {
507             throw new RuntimeException("Heap segment size overflow.");
508         }
509 
510         // Save the current position
511         long currentPosition = fos.getChannel().position();
512 
513         // seek the position to write length
514         fos.getChannel().position(currentSegmentStart);
515 
516         int dumpLen = (int) dumpLenLong;
517 
518         // write length as integer
519         fos.write((dumpLen >>> 24) & 0xFF);
520         fos.write((dumpLen >>> 16) & 0xFF);
521         fos.write((dumpLen >>> 8) & 0xFF);
522         fos.write((dumpLen >>> 0) & 0xFF);
523 
524         //Reset to previous current position
525         fos.getChannel().position(currentPosition);
526     }
527 
528     // get the size in bytes for the requested type
getSizeForType(int type)529     private long getSizeForType(int type) throws IOException {
530         switch (type) {
531             case TypeArrayKlass.T_BOOLEAN:
532                 return BOOLEAN_SIZE;
533             case TypeArrayKlass.T_INT:
534                 return INT_SIZE;
535             case TypeArrayKlass.T_CHAR:
536                 return CHAR_SIZE;
537             case TypeArrayKlass.T_SHORT:
538                 return SHORT_SIZE;
539             case TypeArrayKlass.T_BYTE:
540                 return BYTE_SIZE;
541             case TypeArrayKlass.T_LONG:
542                 return LONG_SIZE;
543             case TypeArrayKlass.T_FLOAT:
544                 return FLOAT_SIZE;
545             case TypeArrayKlass.T_DOUBLE:
546                 return DOUBLE_SIZE;
547             default:
548                 throw new RuntimeException(
549                     "Should not reach here: Unknown type: " + type);
550          }
551     }
552 
getArrayHeaderSize(boolean isObjectAarray)553     private int getArrayHeaderSize(boolean isObjectAarray) {
554         return isObjectAarray?
555             ((int) BYTE_SIZE + 2 * (int) INT_SIZE + 2 * (int) OBJ_ID_SIZE):
556             (2 * (int) BYTE_SIZE + 2 * (int) INT_SIZE + (int) OBJ_ID_SIZE);
557     }
558 
559     // Check if we need to truncate an array
calculateArrayMaxLength(long originalArrayLength, int headerSize, long typeSize, String typeName)560     private int calculateArrayMaxLength(long originalArrayLength,
561                                         int headerSize,
562                                         long typeSize,
563                                         String typeName) throws IOException {
564 
565         long length = originalArrayLength;
566 
567         // now get the current position to calculate length
568         long dumpEnd = fos.getChannel().position();
569         long originalLengthInBytes = originalArrayLength * typeSize;
570 
571         // calculate the length of heap data
572         long currentRecordLength = (dumpEnd - currentSegmentStart - 4L);
573         if (currentRecordLength > 0 &&
574             (currentRecordLength + headerSize + originalLengthInBytes) > MAX_U4_VALUE) {
575             fillInHeapRecordLength();
576             currentSegmentStart = 0;
577             writeHeapRecordPrologue();
578             currentRecordLength = 0;
579         }
580 
581         // Calculate the max bytes we can use.
582         long maxBytes = (MAX_U4_VALUE - (headerSize + currentRecordLength));
583 
584         if (originalLengthInBytes > maxBytes) {
585             length = maxBytes/typeSize;
586             System.err.println("WARNING: Cannot dump array of type " + typeName
587                                + " with length " + originalArrayLength
588                                + "; truncating to length " + length);
589         }
590         return (int) length;
591     }
592 
writeClassDumpRecords()593     private void writeClassDumpRecords() throws IOException {
594         ClassLoaderDataGraph cldGraph = VM.getVM().getClassLoaderDataGraph();
595         try {
596              cldGraph.classesDo(new ClassLoaderDataGraph.ClassVisitor() {
597                             public void visit(Klass k) {
598                                 try {
599                                     writeHeapRecordPrologue();
600                                     writeClassDumpRecord(k);
601                                     writeHeapRecordEpilogue();
602                                 } catch (IOException e) {
603                                     throw new RuntimeException(e);
604                                 }
605                             }
606                         });
607         } catch (RuntimeException re) {
608             handleRuntimeException(re);
609         }
610     }
611 
writeClass(Instance instance)612     protected void writeClass(Instance instance) throws IOException {
613         Klass reflectedKlass = java_lang_Class.asKlass(instance);
614         // dump instance record only for primitive type Class objects.
615         // all other Class objects are covered by writeClassDumpRecords.
616         if (reflectedKlass == null) {
617             writeInstance(instance);
618         }
619     }
620 
writeClassDumpRecord(Klass k)621     private void writeClassDumpRecord(Klass k) throws IOException {
622         out.writeByte((byte)HPROF_GC_CLASS_DUMP);
623         writeObjectID(k.getJavaMirror());
624         out.writeInt(DUMMY_STACK_TRACE_ID);
625         Klass superKlass = k.getJavaSuper();
626         if (superKlass != null) {
627             writeObjectID(superKlass.getJavaMirror());
628         } else {
629             writeObjectID(null);
630         }
631 
632         if (k instanceof InstanceKlass) {
633             InstanceKlass ik = (InstanceKlass) k;
634             writeObjectID(ik.getClassLoader());
635             writeObjectID(null);  // ik.getJavaMirror().getSigners());
636             writeObjectID(null);  // ik.getJavaMirror().getProtectionDomain());
637             // two reserved id fields
638             writeObjectID(null);
639             writeObjectID(null);
640             List fields = getInstanceFields(ik);
641             int instSize = getSizeForFields(fields);
642             classDataCache.put(ik, new ClassData(instSize, fields));
643             out.writeInt(instSize);
644 
645             // For now, ignore constant pool - HAT ignores too!
646             // output number of cp entries as zero.
647             out.writeShort((short) 0);
648 
649             List declaredFields = ik.getImmediateFields();
650             List staticFields = new ArrayList();
651             List instanceFields = new ArrayList();
652             Iterator itr = null;
653             for (itr = declaredFields.iterator(); itr.hasNext();) {
654                 Field field = (Field) itr.next();
655                 if (field.isStatic()) {
656                     staticFields.add(field);
657                 } else {
658                     instanceFields.add(field);
659                 }
660             }
661 
662             // dump static field descriptors
663             writeFieldDescriptors(staticFields, ik);
664 
665             // dump instance field descriptors
666             writeFieldDescriptors(instanceFields, null);
667         } else {
668             if (k instanceof ObjArrayKlass) {
669                 ObjArrayKlass oak = (ObjArrayKlass) k;
670                 Klass bottomKlass = oak.getBottomKlass();
671                 if (bottomKlass instanceof InstanceKlass) {
672                     InstanceKlass ik = (InstanceKlass) bottomKlass;
673                     writeObjectID(ik.getClassLoader());
674                     writeObjectID(null); // ik.getJavaMirror().getSigners());
675                     writeObjectID(null); // ik.getJavaMirror().getProtectionDomain());
676                 } else {
677                     writeObjectID(null);
678                     writeObjectID(null);
679                     writeObjectID(null);
680                 }
681             } else {
682                 writeObjectID(null);
683                 writeObjectID(null);
684                 writeObjectID(null);
685             }
686             // two reserved id fields
687             writeObjectID(null);
688             writeObjectID(null);
689             // write zero instance size -- as instance size
690             // is variable for arrays.
691             out.writeInt(0);
692             // no constant pool for array klasses
693             out.writeShort((short) 0);
694             // no static fields for array klasses
695             out.writeShort((short) 0);
696             // no instance fields for array klasses
697             out.writeShort((short) 0);
698         }
699     }
700 
dumpStackTraces()701     private void dumpStackTraces() throws IOException {
702         // write a HPROF_TRACE record without any frames to be referenced as object alloc sites
703         writeHeader(HPROF_TRACE, 3 * (int)INT_SIZE );
704         out.writeInt(DUMMY_STACK_TRACE_ID);
705         out.writeInt(0);                    // thread number
706         out.writeInt(0);                    // frame count
707 
708         int frameSerialNum = 0;
709         int numThreads = 0;
710         Threads threads = VM.getVM().getThreads();
711         for (int i = 0; i < threads.getNumberOfThreads(); i++) {
712             JavaThread thread = threads.getJavaThreadAt(i);
713             Oop threadObj = thread.getThreadObj();
714             if (threadObj != null && !thread.isExiting() && !thread.isHiddenFromExternalView()) {
715 
716                 // dump thread stack trace
717                 ThreadStackTrace st = new ThreadStackTrace(thread);
718                 st.dumpStack(-1);
719                 numThreads++;
720 
721                 // write HPROF_FRAME records for this thread's stack trace
722                 int depth = st.getStackDepth();
723                 int threadFrameStart = frameSerialNum;
724                 for (int j=0; j < depth; j++) {
725                     StackFrameInfo frame = st.stackFrameAt(j);
726                     Method m = frame.getMethod();
727                     int classSerialNum = KlassMap.indexOf(m.getMethodHolder()) + 1;
728                     // the class serial number starts from 1
729                     assert classSerialNum > 0:"class not found";
730                     dumpStackFrame(++frameSerialNum, classSerialNum, m, frame.getBCI());
731                 }
732 
733                 // write HPROF_TRACE record for one thread
734                 writeHeader(HPROF_TRACE, 3 * (int)INT_SIZE + depth * (int)VM.getVM().getOopSize());
735                 int stackSerialNum = numThreads + DUMMY_STACK_TRACE_ID;
736                 out.writeInt(stackSerialNum);      // stack trace serial number
737                 out.writeInt(numThreads);          // thread serial number
738                 out.writeInt(depth);               // frame count
739                 for (int j=1; j <= depth; j++) {
740                     writeObjectID(threadFrameStart + j);
741                 }
742             }
743         }
744     }
745 
dumpStackFrame(int frameSN, int classSN, Method m, int bci)746     private void dumpStackFrame(int frameSN, int classSN, Method m, int bci) throws IOException {
747         int lineNumber;
748         if (m.isNative()) {
749             lineNumber = -3; // native frame
750         } else {
751             lineNumber = m.getLineNumberFromBCI(bci);
752         }
753         // First dump UTF8 if needed
754         writeSymbol(m.getName());                              // method's name
755         writeSymbol(m.getSignature());                         // method's signature
756         writeSymbol(m.getMethodHolder().getSourceFileName());  // source file name
757         // Then write FRAME descriptor
758         writeHeader(HPROF_FRAME, 4 * (int)VM.getVM().getOopSize() + 2 * (int)INT_SIZE);
759         writeObjectID(frameSN);                                  // frame serial number
760         writeSymbolID(m.getName());                              // method's name
761         writeSymbolID(m.getSignature());                         // method's signature
762         writeSymbolID(m.getMethodHolder().getSourceFileName());  // source file name
763         out.writeInt(classSN);                                   // class serial number
764         out.writeInt(lineNumber);                                // line number
765     }
766 
writeJavaThread(JavaThread jt, int index)767     protected void writeJavaThread(JavaThread jt, int index) throws IOException {
768         out.writeByte((byte) HPROF_GC_ROOT_THREAD_OBJ);
769         writeObjectID(jt.getThreadObj());
770         out.writeInt(index);
771         out.writeInt(DUMMY_STACK_TRACE_ID);
772         writeLocalJNIHandles(jt, index);
773     }
774 
writeLocalJNIHandles(JavaThread jt, int index)775     protected void writeLocalJNIHandles(JavaThread jt, int index) throws IOException {
776         final int threadIndex = index;
777         JNIHandleBlock blk = jt.activeHandles();
778         if (blk != null) {
779             try {
780                 blk.oopsDo(new AddressVisitor() {
781                            public void visitAddress(Address handleAddr) {
782                                try {
783                                    if (handleAddr != null) {
784                                        OopHandle oopHandle = handleAddr.getOopHandleAt(0);
785                                        Oop oop = objectHeap.newOop(oopHandle);
786                                        // exclude JNI handles hotspot internal objects
787                                        if (oop != null && isJavaVisible(oop)) {
788                                            out.writeByte((byte) HPROF_GC_ROOT_JNI_LOCAL);
789                                            writeObjectID(oop);
790                                            out.writeInt(threadIndex);
791                                            out.writeInt(EMPTY_FRAME_DEPTH);
792                                        }
793                                    }
794                                } catch (IOException exp) {
795                                    throw new RuntimeException(exp);
796                                }
797                            }
798                            public void visitCompOopAddress(Address handleAddr) {
799                              throw new RuntimeException(
800                                    " Should not reach here. JNIHandles are not compressed \n");
801                            }
802                        });
803             } catch (RuntimeException re) {
804                 handleRuntimeException(re);
805             }
806         }
807     }
808 
writeGlobalJNIHandle(Address handleAddr)809     protected void writeGlobalJNIHandle(Address handleAddr) throws IOException {
810         OopHandle oopHandle = handleAddr.getOopHandleAt(0);
811         Oop oop = objectHeap.newOop(oopHandle);
812         // exclude JNI handles of hotspot internal objects
813         if (oop != null && isJavaVisible(oop)) {
814             out.writeByte((byte) HPROF_GC_ROOT_JNI_GLOBAL);
815             writeObjectID(oop);
816             // use JNIHandle address as ID
817             writeObjectID(getAddressValue(handleAddr));
818         }
819     }
820 
writeObjectArray(ObjArray array)821     protected void writeObjectArray(ObjArray array) throws IOException {
822         int headerSize = getArrayHeaderSize(true);
823         final int length = calculateArrayMaxLength(array.getLength(),
824                                                    headerSize,
825                                                    OBJ_ID_SIZE,
826                                                    "Object");
827         out.writeByte((byte) HPROF_GC_OBJ_ARRAY_DUMP);
828         writeObjectID(array);
829         out.writeInt(DUMMY_STACK_TRACE_ID);
830         out.writeInt(length);
831         writeObjectID(array.getKlass().getJavaMirror());
832         for (int index = 0; index < length; index++) {
833             OopHandle handle = array.getOopHandleAt(index);
834             writeObjectID(getAddressValue(handle));
835         }
836     }
837 
writePrimitiveArray(TypeArray array)838     protected void writePrimitiveArray(TypeArray array) throws IOException {
839         int headerSize = getArrayHeaderSize(false);
840         TypeArrayKlass tak = (TypeArrayKlass) array.getKlass();
841         final int type = (int) tak.getElementType();
842         final String typeName = tak.getElementTypeName();
843         final long typeSize = getSizeForType(type);
844         final int length = calculateArrayMaxLength(array.getLength(),
845                                                    headerSize,
846                                                    typeSize,
847                                                    typeName);
848         out.writeByte((byte) HPROF_GC_PRIM_ARRAY_DUMP);
849         writeObjectID(array);
850         out.writeInt(DUMMY_STACK_TRACE_ID);
851         out.writeInt(length);
852         out.writeByte((byte) type);
853         switch (type) {
854             case TypeArrayKlass.T_BOOLEAN:
855                 writeBooleanArray(array, length);
856                 break;
857             case TypeArrayKlass.T_CHAR:
858                 writeCharArray(array, length);
859                 break;
860             case TypeArrayKlass.T_FLOAT:
861                 writeFloatArray(array, length);
862                 break;
863             case TypeArrayKlass.T_DOUBLE:
864                 writeDoubleArray(array, length);
865                 break;
866             case TypeArrayKlass.T_BYTE:
867                 writeByteArray(array, length);
868                 break;
869             case TypeArrayKlass.T_SHORT:
870                 writeShortArray(array, length);
871                 break;
872             case TypeArrayKlass.T_INT:
873                 writeIntArray(array, length);
874                 break;
875             case TypeArrayKlass.T_LONG:
876                 writeLongArray(array, length);
877                 break;
878             default:
879                 throw new RuntimeException(
880                     "Should not reach here: Unknown type: " + type);
881         }
882     }
883 
writeBooleanArray(TypeArray array, int length)884     private void writeBooleanArray(TypeArray array, int length) throws IOException {
885         for (int index = 0; index < length; index++) {
886              long offset = BOOLEAN_BASE_OFFSET + index * BOOLEAN_SIZE;
887              out.writeBoolean(array.getHandle().getJBooleanAt(offset));
888         }
889     }
890 
writeByteArray(TypeArray array, int length)891     private void writeByteArray(TypeArray array, int length) throws IOException {
892         for (int index = 0; index < length; index++) {
893              long offset = BYTE_BASE_OFFSET + index * BYTE_SIZE;
894              out.writeByte(array.getHandle().getJByteAt(offset));
895         }
896     }
897 
writeShortArray(TypeArray array, int length)898     private void writeShortArray(TypeArray array, int length) throws IOException {
899         for (int index = 0; index < length; index++) {
900              long offset = SHORT_BASE_OFFSET + index * SHORT_SIZE;
901              out.writeShort(array.getHandle().getJShortAt(offset));
902         }
903     }
904 
writeIntArray(TypeArray array, int length)905     private void writeIntArray(TypeArray array, int length) throws IOException {
906         for (int index = 0; index < length; index++) {
907              long offset = INT_BASE_OFFSET + index * INT_SIZE;
908              out.writeInt(array.getHandle().getJIntAt(offset));
909         }
910     }
911 
writeLongArray(TypeArray array, int length)912     private void writeLongArray(TypeArray array, int length) throws IOException {
913         for (int index = 0; index < length; index++) {
914              long offset = LONG_BASE_OFFSET + index * LONG_SIZE;
915              out.writeLong(array.getHandle().getJLongAt(offset));
916         }
917     }
918 
writeCharArray(TypeArray array, int length)919     private void writeCharArray(TypeArray array, int length) throws IOException {
920         for (int index = 0; index < length; index++) {
921              long offset = CHAR_BASE_OFFSET + index * CHAR_SIZE;
922              out.writeChar(array.getHandle().getJCharAt(offset));
923         }
924     }
925 
writeFloatArray(TypeArray array, int length)926     private void writeFloatArray(TypeArray array, int length) throws IOException {
927         for (int index = 0; index < length; index++) {
928              long offset = FLOAT_BASE_OFFSET + index * FLOAT_SIZE;
929              out.writeFloat(array.getHandle().getJFloatAt(offset));
930         }
931     }
932 
writeDoubleArray(TypeArray array, int length)933     private void writeDoubleArray(TypeArray array, int length) throws IOException {
934         for (int index = 0; index < length; index++) {
935              long offset = DOUBLE_BASE_OFFSET + index * DOUBLE_SIZE;
936              out.writeDouble(array.getHandle().getJDoubleAt(offset));
937         }
938     }
939 
writeInstance(Instance instance)940     protected void writeInstance(Instance instance) throws IOException {
941         Klass klass = instance.getKlass();
942         if (klass.getClassLoaderData() == null) {
943             // Ignoring this object since the corresponding Klass is not loaded.
944             // Might be a dormant archive object.
945             return;
946         }
947 
948         out.writeByte((byte) HPROF_GC_INSTANCE_DUMP);
949         writeObjectID(instance);
950         out.writeInt(DUMMY_STACK_TRACE_ID);
951         writeObjectID(klass.getJavaMirror());
952 
953         ClassData cd = (ClassData) classDataCache.get(klass);
954 
955         if (Assert.ASSERTS_ENABLED) {
956             Assert.that(cd != null, "can not get class data for " + klass.getName().asString() + klass.getAddress());
957         }
958         List fields = cd.fields;
959         int size = cd.instSize;
960         out.writeInt(size);
961         for (Iterator itr = fields.iterator(); itr.hasNext();) {
962             writeField((Field) itr.next(), instance);
963         }
964     }
965 
966     //-- Internals only below this point
967 
writeFieldDescriptors(List fields, InstanceKlass ik)968     private void writeFieldDescriptors(List fields, InstanceKlass ik)
969         throws IOException {
970         // ik == null for instance fields.
971         out.writeShort((short) fields.size());
972         for (Iterator itr = fields.iterator(); itr.hasNext();) {
973             Field field = (Field) itr.next();
974             Symbol name = field.getName();
975             writeSymbolID(name);
976             char typeCode = (char) field.getSignature().getByteAt(0);
977             int kind = signatureToHprofKind(typeCode);
978             out.writeByte((byte)kind);
979             if (ik != null) {
980                 // static field
981                 writeField(field, ik.getJavaMirror());
982             }
983         }
984     }
985 
signatureToHprofKind(char ch)986     public static int signatureToHprofKind(char ch) {
987         switch (ch) {
988         case JVM_SIGNATURE_CLASS:
989         case JVM_SIGNATURE_ARRAY:
990             return HPROF_NORMAL_OBJECT;
991         case JVM_SIGNATURE_BOOLEAN:
992             return HPROF_BOOLEAN;
993         case JVM_SIGNATURE_CHAR:
994             return HPROF_CHAR;
995         case JVM_SIGNATURE_FLOAT:
996             return HPROF_FLOAT;
997         case JVM_SIGNATURE_DOUBLE:
998             return HPROF_DOUBLE;
999         case JVM_SIGNATURE_BYTE:
1000             return HPROF_BYTE;
1001         case JVM_SIGNATURE_SHORT:
1002             return HPROF_SHORT;
1003         case JVM_SIGNATURE_INT:
1004             return HPROF_INT;
1005         case JVM_SIGNATURE_LONG:
1006             return HPROF_LONG;
1007         default:
1008             throw new RuntimeException("should not reach here");
1009         }
1010     }
1011 
writeField(Field field, Oop oop)1012     private void writeField(Field field, Oop oop) throws IOException {
1013         char typeCode = (char) field.getSignature().getByteAt(0);
1014         switch (typeCode) {
1015         case JVM_SIGNATURE_BOOLEAN:
1016             out.writeBoolean(((BooleanField)field).getValue(oop));
1017             break;
1018         case JVM_SIGNATURE_CHAR:
1019             out.writeChar(((CharField)field).getValue(oop));
1020             break;
1021         case JVM_SIGNATURE_BYTE:
1022             out.writeByte(((ByteField)field).getValue(oop));
1023             break;
1024         case JVM_SIGNATURE_SHORT:
1025             out.writeShort(((ShortField)field).getValue(oop));
1026             break;
1027         case JVM_SIGNATURE_INT:
1028             out.writeInt(((IntField)field).getValue(oop));
1029             break;
1030         case JVM_SIGNATURE_LONG:
1031             out.writeLong(((LongField)field).getValue(oop));
1032             break;
1033         case JVM_SIGNATURE_FLOAT:
1034             out.writeFloat(((FloatField)field).getValue(oop));
1035             break;
1036         case JVM_SIGNATURE_DOUBLE:
1037             out.writeDouble(((DoubleField)field).getValue(oop));
1038             break;
1039         case JVM_SIGNATURE_CLASS:
1040         case JVM_SIGNATURE_ARRAY: {
1041             if (VM.getVM().isCompressedOopsEnabled()) {
1042               OopHandle handle = ((NarrowOopField)field).getValueAsOopHandle(oop);
1043               writeObjectID(getAddressValue(handle));
1044             } else {
1045               OopHandle handle = ((OopField)field).getValueAsOopHandle(oop);
1046               writeObjectID(getAddressValue(handle));
1047             }
1048             break;
1049         }
1050         default:
1051             throw new RuntimeException("should not reach here");
1052         }
1053     }
1054 
writeHeader(int tag, int len)1055     private void writeHeader(int tag, int len) throws IOException {
1056         out.writeByte((byte)tag);
1057         out.writeInt(0); // current ticks
1058         out.writeInt(len);
1059     }
1060 
writeDummyTrace()1061     private void writeDummyTrace() throws IOException {
1062         writeHeader(HPROF_TRACE, 3 * 4);
1063         out.writeInt(DUMMY_STACK_TRACE_ID);
1064         out.writeInt(0);
1065         out.writeInt(0);
1066     }
1067 
writeClassSymbols(Klass k)1068     private void writeClassSymbols(Klass k) throws IOException {
1069         writeSymbol(k.getName());
1070         if (k instanceof InstanceKlass) {
1071             InstanceKlass ik = (InstanceKlass) k;
1072             List declaredFields = ik.getImmediateFields();
1073             for (Iterator itr = declaredFields.iterator(); itr.hasNext();) {
1074                 Field field = (Field) itr.next();
1075                 writeSymbol(field.getName());
1076             }
1077         }
1078     }
1079 
writeSymbols()1080     private void writeSymbols() throws IOException {
1081         // Write all the symbols that are used by the classes
1082         ClassLoaderDataGraph cldGraph = VM.getVM().getClassLoaderDataGraph();
1083         try {
1084              cldGraph.classesDo(new ClassLoaderDataGraph.ClassVisitor() {
1085                             public void visit(Klass k) {
1086                                 try {
1087                                     writeClassSymbols(k);
1088                                 } catch (IOException e) {
1089                                     throw new RuntimeException(e);
1090                                 }
1091                             }
1092                         });
1093         } catch (RuntimeException re) {
1094             handleRuntimeException(re);
1095         }
1096     }
1097 
writeSymbol(Symbol sym)1098     private void writeSymbol(Symbol sym) throws IOException {
1099         // If name is already written don't write it again.
1100         if (names.add(sym)) {
1101             if(sym != null) {
1102               byte[] buf = sym.asString().getBytes("UTF-8");
1103               writeHeader(HPROF_UTF8, buf.length + OBJ_ID_SIZE);
1104               writeSymbolID(sym);
1105               out.write(buf);
1106            } else {
1107               writeHeader(HPROF_UTF8, 0 + OBJ_ID_SIZE);
1108               writeSymbolID(null);
1109            }
1110         }
1111     }
1112 
writeClasses()1113     private void writeClasses() throws IOException {
1114         // write class list (id, name) association
1115         ClassLoaderDataGraph cldGraph = VM.getVM().getClassLoaderDataGraph();
1116         try {
1117             cldGraph.classesDo(new ClassLoaderDataGraph.ClassVisitor() {
1118                 public void visit(Klass k) {
1119                     try {
1120                         Instance clazz = k.getJavaMirror();
1121                         writeHeader(HPROF_LOAD_CLASS, 2 * (OBJ_ID_SIZE + 4));
1122                         out.writeInt(serialNum);
1123                         writeObjectID(clazz);
1124                         KlassMap.add(serialNum - 1, k);
1125                         out.writeInt(DUMMY_STACK_TRACE_ID);
1126                         writeSymbolID(k.getName());
1127                         serialNum++;
1128                     } catch (IOException exp) {
1129                         throw new RuntimeException(exp);
1130                     }
1131                 }
1132             });
1133         } catch (RuntimeException re) {
1134             handleRuntimeException(re);
1135         }
1136     }
1137 
1138     // writes hprof binary file header
writeFileHeader()1139     private void writeFileHeader() throws IOException {
1140         // version string
1141         out.writeBytes(HPROF_HEADER_1_0_2);
1142         out.writeByte((byte)'\0');
1143 
1144         // write identifier size. we use pointers as identifiers.
1145         out.writeInt(OBJ_ID_SIZE);
1146 
1147         // timestamp -- file creation time.
1148         out.writeLong(System.currentTimeMillis());
1149     }
1150 
1151     // writes unique ID for an object
writeObjectID(Oop oop)1152     private void writeObjectID(Oop oop) throws IOException {
1153         OopHandle handle = (oop != null)? oop.getHandle() : null;
1154         long address = getAddressValue(handle);
1155         writeObjectID(address);
1156     }
1157 
writeSymbolID(Symbol sym)1158     private void writeSymbolID(Symbol sym) throws IOException {
1159         assert names.contains(sym);
1160         long address = (sym != null) ? getAddressValue(sym.getAddress()) : getAddressValue(null);
1161         writeObjectID(address);
1162     }
1163 
writeObjectID(long address)1164     private void writeObjectID(long address) throws IOException {
1165         if (OBJ_ID_SIZE == 4) {
1166             out.writeInt((int) address);
1167         } else {
1168             out.writeLong(address);
1169         }
1170     }
1171 
getAddressValue(Address addr)1172     private long getAddressValue(Address addr) {
1173         return (addr == null)? 0L : dbg.getAddressValue(addr);
1174     }
1175 
1176     // get all declared as well as inherited (directly/indirectly) fields
getInstanceFields(InstanceKlass ik)1177     private static List/*<Field>*/ getInstanceFields(InstanceKlass ik) {
1178         InstanceKlass klass = ik;
1179         List res = new ArrayList();
1180         while (klass != null) {
1181             List curFields = klass.getImmediateFields();
1182             for (Iterator itr = curFields.iterator(); itr.hasNext();) {
1183                 Field f = (Field) itr.next();
1184                 if (! f.isStatic()) {
1185                     res.add(f);
1186                 }
1187             }
1188             klass = (InstanceKlass) klass.getSuper();
1189         }
1190         return res;
1191     }
1192 
1193     // get size in bytes (in stream) required for given fields.  Note
1194     // that this is not the same as object size in heap. The size in
1195     // heap will include size of padding/alignment bytes as well.
getSizeForFields(List fields)1196     private int getSizeForFields(List fields) {
1197         int size = 0;
1198         for (Iterator itr = fields.iterator(); itr.hasNext();) {
1199             Field field = (Field) itr.next();
1200             char typeCode = (char) field.getSignature().getByteAt(0);
1201             switch (typeCode) {
1202             case JVM_SIGNATURE_BOOLEAN:
1203             case JVM_SIGNATURE_BYTE:
1204                 size++;
1205                 break;
1206             case JVM_SIGNATURE_CHAR:
1207             case JVM_SIGNATURE_SHORT:
1208                 size += 2;
1209                 break;
1210             case JVM_SIGNATURE_INT:
1211             case JVM_SIGNATURE_FLOAT:
1212                 size += 4;
1213                 break;
1214             case JVM_SIGNATURE_CLASS:
1215             case JVM_SIGNATURE_ARRAY:
1216                 size += OBJ_ID_SIZE;
1217                 break;
1218             case JVM_SIGNATURE_LONG:
1219             case JVM_SIGNATURE_DOUBLE:
1220                 size += 8;
1221                 break;
1222             default:
1223                 throw new RuntimeException("should not reach here");
1224             }
1225         }
1226         return size;
1227     }
1228 
1229     // We don't have allocation site info. We write a dummy
1230     // stack trace with this id.
1231     private static final int DUMMY_STACK_TRACE_ID = 1;
1232     private static final int EMPTY_FRAME_DEPTH = -1;
1233 
1234     private DataOutputStream out;
1235     private FileOutputStream fos;
1236     private Debugger dbg;
1237     private ObjectHeap objectHeap;
1238     private ArrayList<Klass> KlassMap;
1239 
1240     // oopSize of the debuggee
1241     private int OBJ_ID_SIZE;
1242 
1243     // Added for hprof file format 1.0.2 support
1244     private boolean useSegmentedHeapDump;
1245     private long currentSegmentStart;
1246 
1247     private long BOOLEAN_BASE_OFFSET;
1248     private long BYTE_BASE_OFFSET;
1249     private long CHAR_BASE_OFFSET;
1250     private long SHORT_BASE_OFFSET;
1251     private long INT_BASE_OFFSET;
1252     private long LONG_BASE_OFFSET;
1253     private long FLOAT_BASE_OFFSET;
1254     private long DOUBLE_BASE_OFFSET;
1255     private long OBJECT_BASE_OFFSET;
1256 
1257     private long BOOLEAN_SIZE;
1258     private long BYTE_SIZE;
1259     private long CHAR_SIZE;
1260     private long SHORT_SIZE;
1261     private long INT_SIZE;
1262     private long LONG_SIZE;
1263     private long FLOAT_SIZE;
1264     private long DOUBLE_SIZE;
1265 
1266     private static class ClassData {
1267         int instSize;
1268         List fields;
1269 
ClassData(int instSize, List fields)1270         ClassData(int instSize, List fields) {
1271             this.instSize = instSize;
1272             this.fields = fields;
1273         }
1274     }
1275 
1276     private Map classDataCache = new HashMap(); // <InstanceKlass, ClassData>
1277 }
1278