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