Mercurial > hg > graal-compiler
comparison agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java @ 0:a61af66fc99e jdk7-b24
Initial load
author | duke |
---|---|
date | Sat, 01 Dec 2007 00:00:00 +0000 |
parents | |
children | ba764ed4b6f2 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:a61af66fc99e |
---|---|
1 /* | |
2 * Copyright 2004-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
20 * CA 95054 USA or visit www.sun.com if you need additional information or | |
21 * have any 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 | |
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" (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 | |
297 public class HeapHprofBinWriter extends AbstractHeapGraphWriter { | |
298 // hprof binary file header | |
299 private static final String HPROF_HEADER = "JAVA PROFILE 1.0.1"; | |
300 | |
301 // constants in enum HprofTag | |
302 private static final int HPROF_UTF8 = 0x01; | |
303 private static final int HPROF_LOAD_CLASS = 0x02; | |
304 private static final int HPROF_UNLOAD_CLASS = 0x03; | |
305 private static final int HPROF_FRAME = 0x04; | |
306 private static final int HPROF_TRACE = 0x05; | |
307 private static final int HPROF_ALLOC_SITES = 0x06; | |
308 private static final int HPROF_HEAP_SUMMARY = 0x07; | |
309 private static final int HPROF_START_THREAD = 0x0A; | |
310 private static final int HPROF_END_THREAD = 0x0B; | |
311 private static final int HPROF_HEAP_DUMP = 0x0C; | |
312 private static final int HPROF_CPU_SAMPLES = 0x0D; | |
313 private static final int HPROF_CONTROL_SETTINGS = 0x0E; | |
314 | |
315 // Heap dump constants | |
316 // constants in enum HprofGcTag | |
317 private static final int HPROF_GC_ROOT_UNKNOWN = 0xFF; | |
318 private static final int HPROF_GC_ROOT_JNI_GLOBAL = 0x01; | |
319 private static final int HPROF_GC_ROOT_JNI_LOCAL = 0x02; | |
320 private static final int HPROF_GC_ROOT_JAVA_FRAME = 0x03; | |
321 private static final int HPROF_GC_ROOT_NATIVE_STACK = 0x04; | |
322 private static final int HPROF_GC_ROOT_STICKY_CLASS = 0x05; | |
323 private static final int HPROF_GC_ROOT_THREAD_BLOCK = 0x06; | |
324 private static final int HPROF_GC_ROOT_MONITOR_USED = 0x07; | |
325 private static final int HPROF_GC_ROOT_THREAD_OBJ = 0x08; | |
326 private static final int HPROF_GC_CLASS_DUMP = 0x20; | |
327 private static final int HPROF_GC_INSTANCE_DUMP = 0x21; | |
328 private static final int HPROF_GC_OBJ_ARRAY_DUMP = 0x22; | |
329 private static final int HPROF_GC_PRIM_ARRAY_DUMP = 0x23; | |
330 | |
331 // constants in enum HprofType | |
332 private static final int HPROF_ARRAY_OBJECT = 1; | |
333 private static final int HPROF_NORMAL_OBJECT = 2; | |
334 private static final int HPROF_BOOLEAN = 4; | |
335 private static final int HPROF_CHAR = 5; | |
336 private static final int HPROF_FLOAT = 6; | |
337 private static final int HPROF_DOUBLE = 7; | |
338 private static final int HPROF_BYTE = 8; | |
339 private static final int HPROF_SHORT = 9; | |
340 private static final int HPROF_INT = 10; | |
341 private static final int HPROF_LONG = 11; | |
342 | |
343 // Java type codes | |
344 private static final int JVM_SIGNATURE_BOOLEAN = 'Z'; | |
345 private static final int JVM_SIGNATURE_CHAR = 'C'; | |
346 private static final int JVM_SIGNATURE_BYTE = 'B'; | |
347 private static final int JVM_SIGNATURE_SHORT = 'S'; | |
348 private static final int JVM_SIGNATURE_INT = 'I'; | |
349 private static final int JVM_SIGNATURE_LONG = 'J'; | |
350 private static final int JVM_SIGNATURE_FLOAT = 'F'; | |
351 private static final int JVM_SIGNATURE_DOUBLE = 'D'; | |
352 private static final int JVM_SIGNATURE_ARRAY = '['; | |
353 private static final int JVM_SIGNATURE_CLASS = 'L'; | |
354 | |
355 | |
356 public synchronized void write(String fileName) throws IOException { | |
357 // open file stream and create buffered data output stream | |
358 FileOutputStream fos = new FileOutputStream(fileName); | |
359 FileChannel chn = fos.getChannel(); | |
360 out = new DataOutputStream(new BufferedOutputStream(fos)); | |
361 | |
362 VM vm = VM.getVM(); | |
363 dbg = vm.getDebugger(); | |
364 objectHeap = vm.getObjectHeap(); | |
365 symTbl = vm.getSymbolTable(); | |
366 | |
367 OBJ_ID_SIZE = (int) vm.getOopSize(); | |
368 | |
369 BOOLEAN_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_BOOLEAN); | |
370 BYTE_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_BYTE); | |
371 CHAR_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_CHAR); | |
372 SHORT_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_SHORT); | |
373 INT_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_INT); | |
374 LONG_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_LONG); | |
375 FLOAT_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_FLOAT); | |
376 DOUBLE_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_DOUBLE); | |
377 OBJECT_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_OBJECT); | |
378 | |
379 BOOLEAN_SIZE = objectHeap.getBooleanSize(); | |
380 BYTE_SIZE = objectHeap.getByteSize(); | |
381 CHAR_SIZE = objectHeap.getCharSize(); | |
382 SHORT_SIZE = objectHeap.getShortSize(); | |
383 INT_SIZE = objectHeap.getIntSize(); | |
384 LONG_SIZE = objectHeap.getLongSize(); | |
385 FLOAT_SIZE = objectHeap.getFloatSize(); | |
386 DOUBLE_SIZE = objectHeap.getDoubleSize(); | |
387 | |
388 // hprof bin format header | |
389 writeFileHeader(); | |
390 | |
391 // dummy stack trace without any frames so that | |
392 // HAT can be run without -stack false option | |
393 writeDummyTrace(); | |
394 | |
395 // hprof UTF-8 symbols section | |
396 writeSymbols(); | |
397 // HPROF_LOAD_CLASS records for all classes | |
398 writeClasses(); | |
399 | |
400 // write heap data now | |
401 out.writeByte((byte)HPROF_HEAP_DUMP); | |
402 out.writeInt(0); // relative timestamp | |
403 | |
404 // remember position of dump length, we will fixup | |
405 // length later - hprof format requires length. | |
406 out.flush(); | |
407 long dumpStart = chn.position(); | |
408 | |
409 // write dummy length of 0 and we'll fix it later. | |
410 out.writeInt(0); | |
411 | |
412 // write CLASS_DUMP records | |
413 writeClassDumpRecords(); | |
414 | |
415 // this will write heap data into the buffer stream | |
416 super.write(); | |
417 | |
418 // flush buffer stream and throw it. | |
419 out.flush(); | |
420 out = null; | |
421 | |
422 // now get current position to calculate length | |
423 long dumpEnd = chn.position(); | |
424 // calculate length of heap data | |
425 int dumpLen = (int) (dumpEnd - dumpStart - 4); | |
426 | |
427 // seek the position to write length | |
428 chn.position(dumpStart); | |
429 | |
430 // write length as integer | |
431 fos.write((dumpLen >>> 24) & 0xFF); | |
432 fos.write((dumpLen >>> 16) & 0xFF); | |
433 fos.write((dumpLen >>> 8) & 0xFF); | |
434 fos.write((dumpLen >>> 0) & 0xFF); | |
435 | |
436 // close the file stream | |
437 fos.close(); | |
438 } | |
439 | |
440 private void writeClassDumpRecords() throws IOException { | |
441 SystemDictionary sysDict = VM.getVM().getSystemDictionary(); | |
442 try { | |
443 sysDict.allClassesDo(new SystemDictionary.ClassVisitor() { | |
444 public void visit(Klass k) { | |
445 try { | |
446 writeClassDumpRecord(k); | |
447 } catch (IOException e) { | |
448 throw new RuntimeException(e); | |
449 } | |
450 } | |
451 }); | |
452 } catch (RuntimeException re) { | |
453 handleRuntimeException(re); | |
454 } | |
455 } | |
456 | |
457 protected void writeClass(Instance instance) throws IOException { | |
458 Klass reflectedKlass = OopUtilities.classOopToKlass(instance); | |
459 // dump instance record only for primitive type Class objects. | |
460 // all other Class objects are covered by writeClassDumpRecords. | |
461 if (reflectedKlass == null) { | |
462 writeInstance(instance); | |
463 } | |
464 } | |
465 | |
466 private void writeClassDumpRecord(Klass k) throws IOException { | |
467 out.writeByte((byte)HPROF_GC_CLASS_DUMP); | |
468 writeObjectID(k.getJavaMirror()); | |
469 out.writeInt(DUMMY_STACK_TRACE_ID); | |
470 Klass superKlass = k.getJavaSuper(); | |
471 if (superKlass != null) { | |
472 writeObjectID(superKlass.getJavaMirror()); | |
473 } else { | |
474 writeObjectID(null); | |
475 } | |
476 | |
477 if (k instanceof InstanceKlass) { | |
478 InstanceKlass ik = (InstanceKlass) k; | |
479 writeObjectID(ik.getClassLoader()); | |
480 writeObjectID(ik.getSigners()); | |
481 writeObjectID(ik.getProtectionDomain()); | |
482 // two reserved id fields | |
483 writeObjectID(null); | |
484 writeObjectID(null); | |
485 List fields = getInstanceFields(ik); | |
486 int instSize = getSizeForFields(fields); | |
487 classDataCache.put(ik, new ClassData(instSize, fields)); | |
488 out.writeInt(instSize); | |
489 | |
490 // For now, ignore constant pool - HAT ignores too! | |
491 // output number of cp entries as zero. | |
492 out.writeShort((short) 0); | |
493 | |
494 List declaredFields = ik.getImmediateFields(); | |
495 List staticFields = new ArrayList(); | |
496 List instanceFields = new ArrayList(); | |
497 Iterator itr = null; | |
498 for (itr = declaredFields.iterator(); itr.hasNext();) { | |
499 Field field = (Field) itr.next(); | |
500 if (field.isStatic()) { | |
501 staticFields.add(field); | |
502 } else { | |
503 instanceFields.add(field); | |
504 } | |
505 } | |
506 | |
507 // dump static field descriptors | |
508 writeFieldDescriptors(staticFields, ik); | |
509 | |
510 // dump instance field descriptors | |
511 writeFieldDescriptors(instanceFields, null); | |
512 } else { | |
513 if (k instanceof ObjArrayKlass) { | |
514 ObjArrayKlass oak = (ObjArrayKlass) k; | |
515 Klass bottomKlass = oak.getBottomKlass(); | |
516 if (bottomKlass instanceof InstanceKlass) { | |
517 InstanceKlass ik = (InstanceKlass) bottomKlass; | |
518 writeObjectID(ik.getClassLoader()); | |
519 writeObjectID(ik.getSigners()); | |
520 writeObjectID(ik.getProtectionDomain()); | |
521 } else { | |
522 writeObjectID(null); | |
523 writeObjectID(null); | |
524 writeObjectID(null); | |
525 } | |
526 } else { | |
527 writeObjectID(null); | |
528 writeObjectID(null); | |
529 writeObjectID(null); | |
530 } | |
531 // two reserved id fields | |
532 writeObjectID(null); | |
533 writeObjectID(null); | |
534 // write zero instance size -- as instance size | |
535 // is variable for arrays. | |
536 out.writeInt(0); | |
537 // no constant pool for array klasses | |
538 out.writeShort((short) 0); | |
539 // no static fields for array klasses | |
540 out.writeShort((short) 0); | |
541 // no instance fields for array klasses | |
542 out.writeShort((short) 0); | |
543 } | |
544 } | |
545 | |
546 protected void writeJavaThread(JavaThread jt, int index) throws IOException { | |
547 out.writeByte((byte) HPROF_GC_ROOT_THREAD_OBJ); | |
548 writeObjectID(jt.getThreadObj()); | |
549 out.writeInt(index); | |
550 out.writeInt(DUMMY_STACK_TRACE_ID); | |
551 writeLocalJNIHandles(jt, index); | |
552 } | |
553 | |
554 protected void writeLocalJNIHandles(JavaThread jt, int index) throws IOException { | |
555 final int threadIndex = index; | |
556 JNIHandleBlock blk = jt.activeHandles(); | |
557 if (blk != null) { | |
558 try { | |
559 blk.oopsDo(new AddressVisitor() { | |
560 public void visitAddress(Address handleAddr) { | |
561 try { | |
562 if (handleAddr != null) { | |
563 OopHandle oopHandle = handleAddr.getOopHandleAt(0); | |
564 Oop oop = objectHeap.newOop(oopHandle); | |
565 // exclude JNI handles hotspot internal objects | |
566 if (oop != null && isJavaVisible(oop)) { | |
567 out.writeByte((byte) HPROF_GC_ROOT_JNI_LOCAL); | |
568 writeObjectID(oop); | |
569 out.writeInt(threadIndex); | |
570 out.writeInt(EMPTY_FRAME_DEPTH); | |
571 } | |
572 } | |
573 } catch (IOException exp) { | |
574 throw new RuntimeException(exp); | |
575 } | |
576 } | |
577 }); | |
578 } catch (RuntimeException re) { | |
579 handleRuntimeException(re); | |
580 } | |
581 } | |
582 } | |
583 | |
584 protected void writeGlobalJNIHandle(Address handleAddr) throws IOException { | |
585 OopHandle oopHandle = handleAddr.getOopHandleAt(0); | |
586 Oop oop = objectHeap.newOop(oopHandle); | |
587 // exclude JNI handles of hotspot internal objects | |
588 if (oop != null && isJavaVisible(oop)) { | |
589 out.writeByte((byte) HPROF_GC_ROOT_JNI_GLOBAL); | |
590 writeObjectID(oop); | |
591 // use JNIHandle address as ID | |
592 writeObjectID(getAddressValue(handleAddr)); | |
593 } | |
594 } | |
595 | |
596 protected void writeObjectArray(ObjArray array) throws IOException { | |
597 out.writeByte((byte) HPROF_GC_OBJ_ARRAY_DUMP); | |
598 writeObjectID(array); | |
599 out.writeInt(DUMMY_STACK_TRACE_ID); | |
600 out.writeInt((int) array.getLength()); | |
601 writeObjectID(array.getKlass().getJavaMirror()); | |
602 final int length = (int) array.getLength(); | |
603 for (int index = 0; index < length; index++) { | |
604 long offset = OBJECT_BASE_OFFSET + index * OBJ_ID_SIZE; | |
605 OopHandle handle = array.getHandle().getOopHandleAt(offset); | |
606 writeObjectID(getAddressValue(handle)); | |
607 } | |
608 } | |
609 | |
610 protected void writePrimitiveArray(TypeArray array) throws IOException { | |
611 out.writeByte((byte) HPROF_GC_PRIM_ARRAY_DUMP); | |
612 writeObjectID(array); | |
613 out.writeInt(DUMMY_STACK_TRACE_ID); | |
614 out.writeInt((int) array.getLength()); | |
615 TypeArrayKlass tak = (TypeArrayKlass) array.getKlass(); | |
616 final int type = (int) tak.getElementType(); | |
617 out.writeByte((byte) type); | |
618 switch (type) { | |
619 case TypeArrayKlass.T_BOOLEAN: | |
620 writeBooleanArray(array); | |
621 break; | |
622 case TypeArrayKlass.T_CHAR: | |
623 writeCharArray(array); | |
624 break; | |
625 case TypeArrayKlass.T_FLOAT: | |
626 writeFloatArray(array); | |
627 break; | |
628 case TypeArrayKlass.T_DOUBLE: | |
629 writeDoubleArray(array); | |
630 break; | |
631 case TypeArrayKlass.T_BYTE: | |
632 writeByteArray(array); | |
633 break; | |
634 case TypeArrayKlass.T_SHORT: | |
635 writeShortArray(array); | |
636 break; | |
637 case TypeArrayKlass.T_INT: | |
638 writeIntArray(array); | |
639 break; | |
640 case TypeArrayKlass.T_LONG: | |
641 writeLongArray(array); | |
642 break; | |
643 default: | |
644 throw new RuntimeException("should not reach here"); | |
645 } | |
646 } | |
647 | |
648 private void writeBooleanArray(TypeArray array) throws IOException { | |
649 final int length = (int) array.getLength(); | |
650 for (int index = 0; index < length; index++) { | |
651 long offset = BOOLEAN_BASE_OFFSET + index * BOOLEAN_SIZE; | |
652 out.writeBoolean(array.getHandle().getJBooleanAt(offset)); | |
653 } | |
654 } | |
655 | |
656 private void writeByteArray(TypeArray array) throws IOException { | |
657 final int length = (int) array.getLength(); | |
658 for (int index = 0; index < length; index++) { | |
659 long offset = BYTE_BASE_OFFSET + index * BYTE_SIZE; | |
660 out.writeByte(array.getHandle().getJByteAt(offset)); | |
661 } | |
662 } | |
663 | |
664 private void writeShortArray(TypeArray array) throws IOException { | |
665 final int length = (int) array.getLength(); | |
666 for (int index = 0; index < length; index++) { | |
667 long offset = SHORT_BASE_OFFSET + index * SHORT_SIZE; | |
668 out.writeShort(array.getHandle().getJShortAt(offset)); | |
669 } | |
670 } | |
671 | |
672 private void writeIntArray(TypeArray array) throws IOException { | |
673 final int length = (int) array.getLength(); | |
674 for (int index = 0; index < length; index++) { | |
675 long offset = INT_BASE_OFFSET + index * INT_SIZE; | |
676 out.writeInt(array.getHandle().getJIntAt(offset)); | |
677 } | |
678 } | |
679 | |
680 private void writeLongArray(TypeArray array) throws IOException { | |
681 final int length = (int) array.getLength(); | |
682 for (int index = 0; index < length; index++) { | |
683 long offset = LONG_BASE_OFFSET + index * LONG_SIZE; | |
684 out.writeLong(array.getHandle().getJLongAt(offset)); | |
685 } | |
686 } | |
687 | |
688 private void writeCharArray(TypeArray array) throws IOException { | |
689 final int length = (int) array.getLength(); | |
690 for (int index = 0; index < length; index++) { | |
691 long offset = CHAR_BASE_OFFSET + index * CHAR_SIZE; | |
692 out.writeChar(array.getHandle().getJCharAt(offset)); | |
693 } | |
694 } | |
695 | |
696 private void writeFloatArray(TypeArray array) throws IOException { | |
697 final int length = (int) array.getLength(); | |
698 for (int index = 0; index < length; index++) { | |
699 long offset = FLOAT_BASE_OFFSET + index * FLOAT_SIZE; | |
700 out.writeFloat(array.getHandle().getJFloatAt(offset)); | |
701 } | |
702 } | |
703 | |
704 private void writeDoubleArray(TypeArray array) throws IOException { | |
705 final int length = (int) array.getLength(); | |
706 for (int index = 0; index < length; index++) { | |
707 long offset = DOUBLE_BASE_OFFSET + index * DOUBLE_SIZE; | |
708 out.writeDouble(array.getHandle().getJDoubleAt(offset)); | |
709 } | |
710 } | |
711 | |
712 protected void writeInstance(Instance instance) throws IOException { | |
713 out.writeByte((byte) HPROF_GC_INSTANCE_DUMP); | |
714 writeObjectID(instance); | |
715 out.writeInt(DUMMY_STACK_TRACE_ID); | |
716 Klass klass = instance.getKlass(); | |
717 writeObjectID(klass.getJavaMirror()); | |
718 | |
719 ClassData cd = (ClassData) classDataCache.get(klass); | |
720 if (Assert.ASSERTS_ENABLED) { | |
721 Assert.that(cd != null, "can not get class data for " + klass.getName().asString() + klass.getHandle()); | |
722 } | |
723 List fields = cd.fields; | |
724 int size = cd.instSize; | |
725 out.writeInt(size); | |
726 for (Iterator itr = fields.iterator(); itr.hasNext();) { | |
727 writeField((Field) itr.next(), instance); | |
728 } | |
729 } | |
730 | |
731 //-- Internals only below this point | |
732 | |
733 private void writeFieldDescriptors(List fields, InstanceKlass ik) | |
734 throws IOException { | |
735 // ik == null for instance fields. | |
736 out.writeShort((short) fields.size()); | |
737 for (Iterator itr = fields.iterator(); itr.hasNext();) { | |
738 Field field = (Field) itr.next(); | |
739 Symbol name = symTbl.probe(field.getID().getName()); | |
740 writeObjectID(name); | |
741 char typeCode = (char) field.getSignature().getByteAt(0); | |
742 int kind = signatureToHprofKind(typeCode); | |
743 out.writeByte((byte)kind); | |
744 if (ik != null) { | |
745 // static field | |
746 writeField(field, ik); | |
747 } | |
748 } | |
749 } | |
750 | |
751 public static int signatureToHprofKind(char ch) { | |
752 switch (ch) { | |
753 case JVM_SIGNATURE_CLASS: | |
754 case JVM_SIGNATURE_ARRAY: | |
755 return HPROF_NORMAL_OBJECT; | |
756 case JVM_SIGNATURE_BOOLEAN: | |
757 return HPROF_BOOLEAN; | |
758 case JVM_SIGNATURE_CHAR: | |
759 return HPROF_CHAR; | |
760 case JVM_SIGNATURE_FLOAT: | |
761 return HPROF_FLOAT; | |
762 case JVM_SIGNATURE_DOUBLE: | |
763 return HPROF_DOUBLE; | |
764 case JVM_SIGNATURE_BYTE: | |
765 return HPROF_BYTE; | |
766 case JVM_SIGNATURE_SHORT: | |
767 return HPROF_SHORT; | |
768 case JVM_SIGNATURE_INT: | |
769 return HPROF_INT; | |
770 case JVM_SIGNATURE_LONG: | |
771 return HPROF_LONG; | |
772 default: | |
773 throw new RuntimeException("should not reach here"); | |
774 } | |
775 } | |
776 | |
777 private void writeField(Field field, Oop oop) throws IOException { | |
778 char typeCode = (char) field.getSignature().getByteAt(0); | |
779 switch (typeCode) { | |
780 case JVM_SIGNATURE_BOOLEAN: | |
781 out.writeBoolean(((BooleanField)field).getValue(oop)); | |
782 break; | |
783 case JVM_SIGNATURE_CHAR: | |
784 out.writeChar(((CharField)field).getValue(oop)); | |
785 break; | |
786 case JVM_SIGNATURE_BYTE: | |
787 out.writeByte(((ByteField)field).getValue(oop)); | |
788 break; | |
789 case JVM_SIGNATURE_SHORT: | |
790 out.writeShort(((ShortField)field).getValue(oop)); | |
791 break; | |
792 case JVM_SIGNATURE_INT: | |
793 out.writeInt(((IntField)field).getValue(oop)); | |
794 break; | |
795 case JVM_SIGNATURE_LONG: | |
796 out.writeLong(((LongField)field).getValue(oop)); | |
797 break; | |
798 case JVM_SIGNATURE_FLOAT: | |
799 out.writeFloat(((FloatField)field).getValue(oop)); | |
800 break; | |
801 case JVM_SIGNATURE_DOUBLE: | |
802 out.writeDouble(((DoubleField)field).getValue(oop)); | |
803 break; | |
804 case JVM_SIGNATURE_CLASS: | |
805 case JVM_SIGNATURE_ARRAY: { | |
806 OopHandle handle = ((OopField)field).getValueAsOopHandle(oop); | |
807 writeObjectID(getAddressValue(handle)); | |
808 break; | |
809 } | |
810 default: | |
811 throw new RuntimeException("should not reach here"); | |
812 } | |
813 } | |
814 | |
815 private void writeHeader(int tag, int len) throws IOException { | |
816 out.writeByte((byte)tag); | |
817 out.writeInt(0); // current ticks | |
818 out.writeInt(len); | |
819 } | |
820 | |
821 private void writeDummyTrace() throws IOException { | |
822 writeHeader(HPROF_TRACE, 3 * 4); | |
823 out.writeInt(DUMMY_STACK_TRACE_ID); | |
824 out.writeInt(0); | |
825 out.writeInt(0); | |
826 } | |
827 | |
828 private void writeSymbols() throws IOException { | |
829 try { | |
830 symTbl.symbolsDo(new SymbolTable.SymbolVisitor() { | |
831 public void visit(Symbol sym) { | |
832 try { | |
833 writeSymbol(sym); | |
834 } catch (IOException exp) { | |
835 throw new RuntimeException(exp); | |
836 } | |
837 } | |
838 }); | |
839 } catch (RuntimeException re) { | |
840 handleRuntimeException(re); | |
841 } | |
842 } | |
843 | |
844 private void writeSymbol(Symbol sym) throws IOException { | |
845 byte[] buf = sym.asString().getBytes("UTF-8"); | |
846 writeHeader(HPROF_UTF8, buf.length + OBJ_ID_SIZE); | |
847 writeObjectID(sym); | |
848 out.write(buf); | |
849 } | |
850 | |
851 private void writeClasses() throws IOException { | |
852 // write class list (id, name) association | |
853 SystemDictionary sysDict = VM.getVM().getSystemDictionary(); | |
854 try { | |
855 sysDict.allClassesDo(new SystemDictionary.ClassVisitor() { | |
856 private int serialNum = 1; | |
857 public void visit(Klass k) { | |
858 try { | |
859 Instance clazz = k.getJavaMirror(); | |
860 writeHeader(HPROF_LOAD_CLASS, 2 * (OBJ_ID_SIZE + 4)); | |
861 out.writeInt(serialNum); | |
862 writeObjectID(clazz); | |
863 out.writeInt(DUMMY_STACK_TRACE_ID); | |
864 writeObjectID(k.getName()); | |
865 serialNum++; | |
866 } catch (IOException exp) { | |
867 throw new RuntimeException(exp); | |
868 } | |
869 } | |
870 }); | |
871 } catch (RuntimeException re) { | |
872 handleRuntimeException(re); | |
873 } | |
874 } | |
875 | |
876 // writes hprof binary file header | |
877 private void writeFileHeader() throws IOException { | |
878 // version string | |
879 out.writeBytes(HPROF_HEADER); | |
880 out.writeByte((byte)'\0'); | |
881 | |
882 // write identifier size. we use pointers as identifiers. | |
883 out.writeInt(OBJ_ID_SIZE); | |
884 | |
885 // timestamp -- file creation time. | |
886 out.writeLong(System.currentTimeMillis()); | |
887 } | |
888 | |
889 // writes unique ID for an object | |
890 private void writeObjectID(Oop oop) throws IOException { | |
891 OopHandle handle = (oop != null)? oop.getHandle() : null; | |
892 long address = getAddressValue(handle); | |
893 writeObjectID(address); | |
894 } | |
895 | |
896 private void writeObjectID(long address) throws IOException { | |
897 if (OBJ_ID_SIZE == 4) { | |
898 out.writeInt((int) address); | |
899 } else { | |
900 out.writeLong(address); | |
901 } | |
902 } | |
903 | |
904 private long getAddressValue(Address addr) { | |
905 return (addr == null)? 0L : dbg.getAddressValue(addr); | |
906 } | |
907 | |
908 // get all declared as well as inherited (directly/indirectly) fields | |
909 private static List/*<Field>*/ getInstanceFields(InstanceKlass ik) { | |
910 InstanceKlass klass = ik; | |
911 List res = new ArrayList(); | |
912 while (klass != null) { | |
913 List curFields = klass.getImmediateFields(); | |
914 for (Iterator itr = curFields.iterator(); itr.hasNext();) { | |
915 Field f = (Field) itr.next(); | |
916 if (! f.isStatic()) { | |
917 res.add(f); | |
918 } | |
919 } | |
920 klass = (InstanceKlass) klass.getSuper(); | |
921 } | |
922 return res; | |
923 } | |
924 | |
925 // get size in bytes (in stream) required for given fields. Note | |
926 // that this is not the same as object size in heap. The size in | |
927 // heap will include size of padding/alignment bytes as well. | |
928 private int getSizeForFields(List fields) { | |
929 int size = 0; | |
930 for (Iterator itr = fields.iterator(); itr.hasNext();) { | |
931 Field field = (Field) itr.next(); | |
932 char typeCode = (char) field.getSignature().getByteAt(0); | |
933 switch (typeCode) { | |
934 case JVM_SIGNATURE_BOOLEAN: | |
935 case JVM_SIGNATURE_BYTE: | |
936 size++; | |
937 break; | |
938 case JVM_SIGNATURE_CHAR: | |
939 case JVM_SIGNATURE_SHORT: | |
940 size += 2; | |
941 break; | |
942 case JVM_SIGNATURE_INT: | |
943 case JVM_SIGNATURE_FLOAT: | |
944 size += 4; | |
945 break; | |
946 case JVM_SIGNATURE_CLASS: | |
947 case JVM_SIGNATURE_ARRAY: | |
948 size += OBJ_ID_SIZE; | |
949 break; | |
950 case JVM_SIGNATURE_LONG: | |
951 case JVM_SIGNATURE_DOUBLE: | |
952 size += 8; | |
953 break; | |
954 default: | |
955 throw new RuntimeException("should not reach here"); | |
956 } | |
957 } | |
958 return size; | |
959 } | |
960 | |
961 // We don't have allocation site info. We write a dummy | |
962 // stack trace with this id. | |
963 private static final int DUMMY_STACK_TRACE_ID = 1; | |
964 private static final int EMPTY_FRAME_DEPTH = -1; | |
965 | |
966 private DataOutputStream out; | |
967 private Debugger dbg; | |
968 private ObjectHeap objectHeap; | |
969 private SymbolTable symTbl; | |
970 | |
971 // oopSize of the debuggee | |
972 private int OBJ_ID_SIZE; | |
973 | |
974 private long BOOLEAN_BASE_OFFSET; | |
975 private long BYTE_BASE_OFFSET; | |
976 private long CHAR_BASE_OFFSET; | |
977 private long SHORT_BASE_OFFSET; | |
978 private long INT_BASE_OFFSET; | |
979 private long LONG_BASE_OFFSET; | |
980 private long FLOAT_BASE_OFFSET; | |
981 private long DOUBLE_BASE_OFFSET; | |
982 private long OBJECT_BASE_OFFSET; | |
983 | |
984 private long BOOLEAN_SIZE; | |
985 private long BYTE_SIZE; | |
986 private long CHAR_SIZE; | |
987 private long SHORT_SIZE; | |
988 private long INT_SIZE; | |
989 private long LONG_SIZE; | |
990 private long FLOAT_SIZE; | |
991 private long DOUBLE_SIZE; | |
992 | |
993 private static class ClassData { | |
994 int instSize; | |
995 List fields; | |
996 ClassData(int instSize, List fields) { | |
997 this.instSize = instSize; | |
998 this.fields = fields; | |
999 } | |
1000 } | |
1001 | |
1002 private Map classDataCache = new HashMap(); // <InstanceKlass, ClassData> | |
1003 } |