Mercurial > hg > truffle
annotate src/share/vm/services/heapDumper.cpp @ 452:00b023ae2d78
6722113: CMS: Incorrect overflow handling during precleaning of Reference lists
Summary: When we encounter marking stack overflow during precleaning of Reference lists, we were using the overflow list mechanism, which can cause problems on account of mutating the mark word of the header because of conflicts with mutator accesses and updates of that field. Instead we should use the usual mechanism for overflow handling in concurrent phases, namely dirtying of the card on which the overflowed object lies. Since precleaning effectively does a form of discovered list processing, albeit with discovery enabled, we needed to adjust some code to be correct in the face of interleaved processing and discovery.
Reviewed-by: apetrusenko, jcoomes
author | ysr |
---|---|
date | Thu, 20 Nov 2008 12:27:41 -0800 |
parents | 4d05b7cb7842 |
children | e9be0e04635a |
rev | line source |
---|---|
0 | 1 /* |
196 | 2 * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. |
0 | 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 # include "incls/_precompiled.incl" | |
26 # include "incls/_heapDumper.cpp.incl" | |
27 | |
28 /* | |
29 * HPROF binary format - description copied from: | |
30 * src/share/demo/jvmti/hprof/hprof_io.c | |
31 * | |
32 * | |
33 * header "JAVA PROFILE 1.0.1" or "JAVA PROFILE 1.0.2" | |
34 * (0-terminated) | |
35 * | |
36 * u4 size of identifiers. Identifiers are used to represent | |
37 * UTF8 strings, objects, stack traces, etc. They usually | |
38 * have the same size as host pointers. For example, on | |
39 * Solaris and Win32, the size is 4. | |
40 * u4 high word | |
41 * u4 low word number of milliseconds since 0:00 GMT, 1/1/70 | |
42 * [record]* a sequence of records. | |
43 * | |
44 * | |
45 * Record format: | |
46 * | |
47 * u1 a TAG denoting the type of the record | |
48 * u4 number of *microseconds* since the time stamp in the | |
49 * header. (wraps around in a little more than an hour) | |
50 * u4 number of bytes *remaining* in the record. Note that | |
51 * this number excludes the tag and the length field itself. | |
52 * [u1]* BODY of the record (a sequence of bytes) | |
53 * | |
54 * | |
55 * The following TAGs are supported: | |
56 * | |
57 * TAG BODY notes | |
58 *---------------------------------------------------------- | |
59 * HPROF_UTF8 a UTF8-encoded name | |
60 * | |
61 * id name ID | |
62 * [u1]* UTF8 characters (no trailing zero) | |
63 * | |
64 * HPROF_LOAD_CLASS a newly loaded class | |
65 * | |
66 * u4 class serial number (> 0) | |
67 * id class object ID | |
68 * u4 stack trace serial number | |
69 * id class name ID | |
70 * | |
71 * HPROF_UNLOAD_CLASS an unloading class | |
72 * | |
73 * u4 class serial_number | |
74 * | |
75 * HPROF_FRAME a Java stack frame | |
76 * | |
77 * id stack frame ID | |
78 * id method name ID | |
79 * id method signature ID | |
80 * id source file name ID | |
81 * u4 class serial number | |
82 * i4 line number. >0: normal | |
83 * -1: unknown | |
84 * -2: compiled method | |
85 * -3: native method | |
86 * | |
87 * HPROF_TRACE a Java stack trace | |
88 * | |
89 * u4 stack trace serial number | |
90 * u4 thread serial number | |
91 * u4 number of frames | |
92 * [id]* stack frame IDs | |
93 * | |
94 * | |
95 * HPROF_ALLOC_SITES a set of heap allocation sites, obtained after GC | |
96 * | |
97 * u2 flags 0x0001: incremental vs. complete | |
98 * 0x0002: sorted by allocation vs. live | |
99 * 0x0004: whether to force a GC | |
100 * u4 cutoff ratio | |
101 * u4 total live bytes | |
102 * u4 total live instances | |
103 * u8 total bytes allocated | |
104 * u8 total instances allocated | |
105 * u4 number of sites that follow | |
106 * [u1 is_array: 0: normal object | |
107 * 2: object array | |
108 * 4: boolean array | |
109 * 5: char array | |
110 * 6: float array | |
111 * 7: double array | |
112 * 8: byte array | |
113 * 9: short array | |
114 * 10: int array | |
115 * 11: long array | |
116 * u4 class serial number (may be zero during startup) | |
117 * u4 stack trace serial number | |
118 * u4 number of bytes alive | |
119 * u4 number of instances alive | |
120 * u4 number of bytes allocated | |
121 * u4]* number of instance allocated | |
122 * | |
123 * HPROF_START_THREAD a newly started thread. | |
124 * | |
125 * u4 thread serial number (> 0) | |
126 * id thread object ID | |
127 * u4 stack trace serial number | |
128 * id thread name ID | |
129 * id thread group name ID | |
130 * id thread group parent name ID | |
131 * | |
132 * HPROF_END_THREAD a terminating thread. | |
133 * | |
134 * u4 thread serial number | |
135 * | |
136 * HPROF_HEAP_SUMMARY heap summary | |
137 * | |
138 * u4 total live bytes | |
139 * u4 total live instances | |
140 * u8 total bytes allocated | |
141 * u8 total instances allocated | |
142 * | |
143 * HPROF_HEAP_DUMP denote a heap dump | |
144 * | |
145 * [heap dump sub-records]* | |
146 * | |
147 * There are four kinds of heap dump sub-records: | |
148 * | |
149 * u1 sub-record type | |
150 * | |
151 * HPROF_GC_ROOT_UNKNOWN unknown root | |
152 * | |
153 * id object ID | |
154 * | |
155 * HPROF_GC_ROOT_THREAD_OBJ thread object | |
156 * | |
157 * id thread object ID (may be 0 for a | |
158 * thread newly attached through JNI) | |
159 * u4 thread sequence number | |
160 * u4 stack trace sequence number | |
161 * | |
162 * HPROF_GC_ROOT_JNI_GLOBAL JNI global ref root | |
163 * | |
164 * id object ID | |
165 * id JNI global ref ID | |
166 * | |
167 * HPROF_GC_ROOT_JNI_LOCAL JNI local ref | |
168 * | |
169 * id object ID | |
170 * u4 thread serial number | |
171 * u4 frame # in stack trace (-1 for empty) | |
172 * | |
173 * HPROF_GC_ROOT_JAVA_FRAME Java stack frame | |
174 * | |
175 * id object ID | |
176 * u4 thread serial number | |
177 * u4 frame # in stack trace (-1 for empty) | |
178 * | |
179 * HPROF_GC_ROOT_NATIVE_STACK Native stack | |
180 * | |
181 * id object ID | |
182 * u4 thread serial number | |
183 * | |
184 * HPROF_GC_ROOT_STICKY_CLASS System class | |
185 * | |
186 * id object ID | |
187 * | |
188 * HPROF_GC_ROOT_THREAD_BLOCK Reference from thread block | |
189 * | |
190 * id object ID | |
191 * u4 thread serial number | |
192 * | |
193 * HPROF_GC_ROOT_MONITOR_USED Busy monitor | |
194 * | |
195 * id object ID | |
196 * | |
197 * HPROF_GC_CLASS_DUMP dump of a class object | |
198 * | |
199 * id class object ID | |
200 * u4 stack trace serial number | |
201 * id super class object ID | |
202 * id class loader object ID | |
203 * id signers object ID | |
204 * id protection domain object ID | |
205 * id reserved | |
206 * id reserved | |
207 * | |
208 * u4 instance size (in bytes) | |
209 * | |
210 * u2 size of constant pool | |
211 * [u2, constant pool index, | |
212 * ty, type | |
213 * 2: object | |
214 * 4: boolean | |
215 * 5: char | |
216 * 6: float | |
217 * 7: double | |
218 * 8: byte | |
219 * 9: short | |
220 * 10: int | |
221 * 11: long | |
222 * vl]* and value | |
223 * | |
224 * u2 number of static fields | |
225 * [id, static field name, | |
226 * ty, type, | |
227 * vl]* and value | |
228 * | |
229 * u2 number of inst. fields (not inc. super) | |
230 * [id, instance field name, | |
231 * ty]* type | |
232 * | |
233 * HPROF_GC_INSTANCE_DUMP dump of a normal object | |
234 * | |
235 * id object ID | |
236 * u4 stack trace serial number | |
237 * id class object ID | |
238 * u4 number of bytes that follow | |
239 * [vl]* instance field values (class, followed | |
240 * by super, super's super ...) | |
241 * | |
242 * HPROF_GC_OBJ_ARRAY_DUMP dump of an object array | |
243 * | |
244 * id array object ID | |
245 * u4 stack trace serial number | |
246 * u4 number of elements | |
247 * id array class ID | |
248 * [id]* elements | |
249 * | |
250 * HPROF_GC_PRIM_ARRAY_DUMP dump of a primitive array | |
251 * | |
252 * id array object ID | |
253 * u4 stack trace serial number | |
254 * u4 number of elements | |
255 * u1 element type | |
256 * 4: boolean array | |
257 * 5: char array | |
258 * 6: float array | |
259 * 7: double array | |
260 * 8: byte array | |
261 * 9: short array | |
262 * 10: int array | |
263 * 11: long array | |
264 * [u1]* elements | |
265 * | |
266 * HPROF_CPU_SAMPLES a set of sample traces of running threads | |
267 * | |
268 * u4 total number of samples | |
269 * u4 # of traces | |
270 * [u4 # of samples | |
271 * u4]* stack trace serial number | |
272 * | |
273 * HPROF_CONTROL_SETTINGS the settings of on/off switches | |
274 * | |
275 * u4 0x00000001: alloc traces on/off | |
276 * 0x00000002: cpu sampling on/off | |
277 * u2 stack trace depth | |
278 * | |
279 * | |
280 * When the header is "JAVA PROFILE 1.0.2" a heap dump can optionally | |
281 * be generated as a sequence of heap dump segments. This sequence is | |
282 * terminated by an end record. The additional tags allowed by format | |
283 * "JAVA PROFILE 1.0.2" are: | |
284 * | |
285 * HPROF_HEAP_DUMP_SEGMENT denote a heap dump segment | |
286 * | |
287 * [heap dump sub-records]* | |
288 * The same sub-record types allowed by HPROF_HEAP_DUMP | |
289 * | |
290 * HPROF_HEAP_DUMP_END denotes the end of a heap dump | |
291 * | |
292 */ | |
293 | |
294 | |
295 // HPROF tags | |
296 | |
297 typedef enum { | |
298 // top-level records | |
299 HPROF_UTF8 = 0x01, | |
300 HPROF_LOAD_CLASS = 0x02, | |
301 HPROF_UNLOAD_CLASS = 0x03, | |
302 HPROF_FRAME = 0x04, | |
303 HPROF_TRACE = 0x05, | |
304 HPROF_ALLOC_SITES = 0x06, | |
305 HPROF_HEAP_SUMMARY = 0x07, | |
306 HPROF_START_THREAD = 0x0A, | |
307 HPROF_END_THREAD = 0x0B, | |
308 HPROF_HEAP_DUMP = 0x0C, | |
309 HPROF_CPU_SAMPLES = 0x0D, | |
310 HPROF_CONTROL_SETTINGS = 0x0E, | |
311 | |
312 // 1.0.2 record types | |
313 HPROF_HEAP_DUMP_SEGMENT = 0x1C, | |
314 HPROF_HEAP_DUMP_END = 0x2C, | |
315 | |
316 // field types | |
317 HPROF_ARRAY_OBJECT = 0x01, | |
318 HPROF_NORMAL_OBJECT = 0x02, | |
319 HPROF_BOOLEAN = 0x04, | |
320 HPROF_CHAR = 0x05, | |
321 HPROF_FLOAT = 0x06, | |
322 HPROF_DOUBLE = 0x07, | |
323 HPROF_BYTE = 0x08, | |
324 HPROF_SHORT = 0x09, | |
325 HPROF_INT = 0x0A, | |
326 HPROF_LONG = 0x0B, | |
327 | |
328 // data-dump sub-records | |
329 HPROF_GC_ROOT_UNKNOWN = 0xFF, | |
330 HPROF_GC_ROOT_JNI_GLOBAL = 0x01, | |
331 HPROF_GC_ROOT_JNI_LOCAL = 0x02, | |
332 HPROF_GC_ROOT_JAVA_FRAME = 0x03, | |
333 HPROF_GC_ROOT_NATIVE_STACK = 0x04, | |
334 HPROF_GC_ROOT_STICKY_CLASS = 0x05, | |
335 HPROF_GC_ROOT_THREAD_BLOCK = 0x06, | |
336 HPROF_GC_ROOT_MONITOR_USED = 0x07, | |
337 HPROF_GC_ROOT_THREAD_OBJ = 0x08, | |
338 HPROF_GC_CLASS_DUMP = 0x20, | |
339 HPROF_GC_INSTANCE_DUMP = 0x21, | |
340 HPROF_GC_OBJ_ARRAY_DUMP = 0x22, | |
341 HPROF_GC_PRIM_ARRAY_DUMP = 0x23 | |
342 } hprofTag; | |
343 | |
344 // Default stack trace ID (used for dummy HPROF_TRACE record) | |
345 enum { | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
346 STACK_TRACE_ID = 1, |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
347 INITIAL_CLASS_COUNT = 200 |
0 | 348 }; |
349 | |
350 | |
351 // Supports I/O operations on a dump file | |
352 | |
353 class DumpWriter : public StackObj { | |
354 private: | |
355 enum { | |
356 io_buffer_size = 8*M | |
357 }; | |
358 | |
359 int _fd; // file descriptor (-1 if dump file not open) | |
360 jlong _bytes_written; // number of byte written to dump file | |
361 | |
362 char* _buffer; // internal buffer | |
363 int _size; | |
364 int _pos; | |
365 | |
366 char* _error; // error message when I/O fails | |
367 | |
368 void set_file_descriptor(int fd) { _fd = fd; } | |
369 int file_descriptor() const { return _fd; } | |
370 | |
371 char* buffer() const { return _buffer; } | |
372 int buffer_size() const { return _size; } | |
373 int position() const { return _pos; } | |
374 void set_position(int pos) { _pos = pos; } | |
375 | |
376 void set_error(const char* error) { _error = (char*)os::strdup(error); } | |
377 | |
378 // all I/O go through this function | |
379 void write_internal(void* s, int len); | |
380 | |
381 public: | |
382 DumpWriter(const char* path); | |
383 ~DumpWriter(); | |
384 | |
385 void close(); | |
386 bool is_open() const { return file_descriptor() >= 0; } | |
387 void flush(); | |
388 | |
389 // total number of bytes written to the disk | |
390 jlong bytes_written() const { return _bytes_written; } | |
391 | |
392 // adjust the number of bytes written to disk (used to keep the count | |
393 // of the number of bytes written in case of rewrites) | |
394 void adjust_bytes_written(jlong n) { _bytes_written += n; } | |
395 | |
396 // number of (buffered) bytes as yet unwritten to the dump file | |
397 jlong bytes_unwritten() const { return (jlong)position(); } | |
398 | |
399 char* error() const { return _error; } | |
400 | |
401 jlong current_offset(); | |
402 void seek_to_offset(jlong pos); | |
403 | |
404 // writer functions | |
405 void write_raw(void* s, int len); | |
406 void write_u1(u1 x) { write_raw((void*)&x, 1); } | |
407 void write_u2(u2 x); | |
408 void write_u4(u4 x); | |
409 void write_u8(u8 x); | |
410 void write_objectID(oop o); | |
411 void write_classID(Klass* k); | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
412 void write_id(u4 x); |
0 | 413 }; |
414 | |
415 DumpWriter::DumpWriter(const char* path) { | |
416 // try to allocate an I/O buffer of io_buffer_size. If there isn't | |
417 // sufficient memory then reduce size until we can allocate something. | |
418 _size = io_buffer_size; | |
419 do { | |
420 _buffer = (char*)os::malloc(_size); | |
421 if (_buffer == NULL) { | |
422 _size = _size >> 1; | |
423 } | |
424 } while (_buffer == NULL && _size > 0); | |
425 assert((_size > 0 && _buffer != NULL) || (_size == 0 && _buffer == NULL), "sanity check"); | |
426 _pos = 0; | |
427 _error = NULL; | |
428 _bytes_written = 0L; | |
429 _fd = os::create_binary_file(path, false); // don't replace existing file | |
430 | |
431 // if the open failed we record the error | |
432 if (_fd < 0) { | |
433 _error = (char*)os::strdup(strerror(errno)); | |
434 } | |
435 } | |
436 | |
437 DumpWriter::~DumpWriter() { | |
438 // flush and close dump file | |
439 if (file_descriptor() >= 0) { | |
440 close(); | |
441 } | |
442 if (_buffer != NULL) os::free(_buffer); | |
443 if (_error != NULL) os::free(_error); | |
444 } | |
445 | |
446 // closes dump file (if open) | |
447 void DumpWriter::close() { | |
448 // flush and close dump file | |
449 if (file_descriptor() >= 0) { | |
450 flush(); | |
451 ::close(file_descriptor()); | |
452 } | |
453 } | |
454 | |
455 // write directly to the file | |
456 void DumpWriter::write_internal(void* s, int len) { | |
457 if (is_open()) { | |
458 int n = ::write(file_descriptor(), s, len); | |
459 if (n > 0) { | |
460 _bytes_written += n; | |
461 } | |
462 if (n != len) { | |
463 if (n < 0) { | |
464 set_error(strerror(errno)); | |
465 } else { | |
466 set_error("file size limit"); | |
467 } | |
468 ::close(file_descriptor()); | |
469 set_file_descriptor(-1); | |
470 } | |
471 } | |
472 } | |
473 | |
474 // write raw bytes | |
475 void DumpWriter::write_raw(void* s, int len) { | |
476 if (is_open()) { | |
477 // flush buffer to make toom | |
478 if ((position()+ len) >= buffer_size()) { | |
479 flush(); | |
480 } | |
481 | |
482 // buffer not available or too big to buffer it | |
483 if ((buffer() == NULL) || (len >= buffer_size())) { | |
484 write_internal(s, len); | |
485 } else { | |
486 // Should optimize this for u1/u2/u4/u8 sizes. | |
487 memcpy(buffer() + position(), s, len); | |
488 set_position(position() + len); | |
489 } | |
490 } | |
491 } | |
492 | |
493 // flush any buffered bytes to the file | |
494 void DumpWriter::flush() { | |
495 if (is_open() && position() > 0) { | |
496 write_internal(buffer(), position()); | |
497 set_position(0); | |
498 } | |
499 } | |
500 | |
501 | |
502 jlong DumpWriter::current_offset() { | |
503 if (is_open()) { | |
504 // the offset is the file offset plus whatever we have buffered | |
505 jlong offset = os::current_file_offset(file_descriptor()); | |
506 assert(offset >= 0, "lseek failed"); | |
507 return offset + (jlong)position(); | |
508 } else { | |
509 return (jlong)-1; | |
510 } | |
511 } | |
512 | |
513 void DumpWriter::seek_to_offset(jlong off) { | |
514 assert(off >= 0, "bad offset"); | |
515 | |
516 // need to flush before seeking | |
517 flush(); | |
518 | |
519 // may be closed due to I/O error | |
520 if (is_open()) { | |
521 jlong n = os::seek_to_file_offset(file_descriptor(), off); | |
522 assert(n >= 0, "lseek failed"); | |
523 } | |
524 } | |
525 | |
526 void DumpWriter::write_u2(u2 x) { | |
527 u2 v; | |
528 Bytes::put_Java_u2((address)&v, x); | |
529 write_raw((void*)&v, 2); | |
530 } | |
531 | |
532 void DumpWriter::write_u4(u4 x) { | |
533 u4 v; | |
534 Bytes::put_Java_u4((address)&v, x); | |
535 write_raw((void*)&v, 4); | |
536 } | |
537 | |
538 void DumpWriter::write_u8(u8 x) { | |
539 u8 v; | |
540 Bytes::put_Java_u8((address)&v, x); | |
541 write_raw((void*)&v, 8); | |
542 } | |
543 | |
544 void DumpWriter::write_objectID(oop o) { | |
545 address a = (address)((uintptr_t)o); | |
546 #ifdef _LP64 | |
547 write_u8((u8)a); | |
548 #else | |
549 write_u4((u4)a); | |
550 #endif | |
551 } | |
552 | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
553 void DumpWriter::write_id(u4 x) { |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
554 #ifdef _LP64 |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
555 write_u8((u8) x); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
556 #else |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
557 write_u4(x); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
558 #endif |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
559 } |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
560 |
0 | 561 // We use java mirror as the class ID |
562 void DumpWriter::write_classID(Klass* k) { | |
563 write_objectID(k->java_mirror()); | |
564 } | |
565 | |
566 | |
567 | |
568 // Support class with a collection of functions used when dumping the heap | |
569 | |
570 class DumperSupport : AllStatic { | |
571 public: | |
572 | |
573 // write a header of the given type | |
574 static void write_header(DumpWriter* writer, hprofTag tag, u4 len); | |
575 | |
576 // returns hprof tag for the given type signature | |
577 static hprofTag sig2tag(symbolOop sig); | |
578 // returns hprof tag for the given basic type | |
579 static hprofTag type2tag(BasicType type); | |
580 | |
581 // returns the size of the instance of the given class | |
582 static u4 instance_size(klassOop k); | |
583 | |
584 // dump a jfloat | |
585 static void dump_float(DumpWriter* writer, jfloat f); | |
586 // dump a jdouble | |
587 static void dump_double(DumpWriter* writer, jdouble d); | |
588 // dumps the raw value of the given field | |
589 static void dump_field_value(DumpWriter* writer, char type, address addr); | |
590 // dumps static fields of the given class | |
591 static void dump_static_fields(DumpWriter* writer, klassOop k); | |
592 // dump the raw values of the instance fields of the given object | |
593 static void dump_instance_fields(DumpWriter* writer, oop o); | |
594 // dumps the definition of the instance fields for a given class | |
595 static void dump_instance_field_descriptors(DumpWriter* writer, klassOop k); | |
596 // creates HPROF_GC_INSTANCE_DUMP record for the given object | |
597 static void dump_instance(DumpWriter* writer, oop o); | |
598 // creates HPROF_GC_CLASS_DUMP record for the given class and each of its | |
599 // array classes | |
600 static void dump_class_and_array_classes(DumpWriter* writer, klassOop k); | |
601 // creates HPROF_GC_CLASS_DUMP record for a given primitive array | |
602 // class (and each multi-dimensional array class too) | |
603 static void dump_basic_type_array_class(DumpWriter* writer, klassOop k); | |
604 | |
605 // creates HPROF_GC_OBJ_ARRAY_DUMP record for the given object array | |
606 static void dump_object_array(DumpWriter* writer, objArrayOop array); | |
607 // creates HPROF_GC_PRIM_ARRAY_DUMP record for the given type array | |
608 static void dump_prim_array(DumpWriter* writer, typeArrayOop array); | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
609 // create HPROF_FRAME record for the given method and bci |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
610 static void dump_stack_frame(DumpWriter* writer, int frame_serial_num, int class_serial_num, methodOop m, int bci); |
0 | 611 }; |
612 | |
613 // write a header of the given type | |
614 void DumperSupport:: write_header(DumpWriter* writer, hprofTag tag, u4 len) { | |
615 writer->write_u1((u1)tag); | |
616 writer->write_u4(0); // current ticks | |
617 writer->write_u4(len); | |
618 } | |
619 | |
620 // returns hprof tag for the given type signature | |
621 hprofTag DumperSupport::sig2tag(symbolOop sig) { | |
622 switch (sig->byte_at(0)) { | |
623 case JVM_SIGNATURE_CLASS : return HPROF_NORMAL_OBJECT; | |
624 case JVM_SIGNATURE_ARRAY : return HPROF_NORMAL_OBJECT; | |
625 case JVM_SIGNATURE_BYTE : return HPROF_BYTE; | |
626 case JVM_SIGNATURE_CHAR : return HPROF_CHAR; | |
627 case JVM_SIGNATURE_FLOAT : return HPROF_FLOAT; | |
628 case JVM_SIGNATURE_DOUBLE : return HPROF_DOUBLE; | |
629 case JVM_SIGNATURE_INT : return HPROF_INT; | |
630 case JVM_SIGNATURE_LONG : return HPROF_LONG; | |
631 case JVM_SIGNATURE_SHORT : return HPROF_SHORT; | |
632 case JVM_SIGNATURE_BOOLEAN : return HPROF_BOOLEAN; | |
633 default : ShouldNotReachHere(); /* to shut up compiler */ return HPROF_BYTE; | |
634 } | |
635 } | |
636 | |
637 hprofTag DumperSupport::type2tag(BasicType type) { | |
638 switch (type) { | |
639 case T_BYTE : return HPROF_BYTE; | |
640 case T_CHAR : return HPROF_CHAR; | |
641 case T_FLOAT : return HPROF_FLOAT; | |
642 case T_DOUBLE : return HPROF_DOUBLE; | |
643 case T_INT : return HPROF_INT; | |
644 case T_LONG : return HPROF_LONG; | |
645 case T_SHORT : return HPROF_SHORT; | |
646 case T_BOOLEAN : return HPROF_BOOLEAN; | |
647 default : ShouldNotReachHere(); /* to shut up compiler */ return HPROF_BYTE; | |
648 } | |
649 } | |
650 | |
651 // dump a jfloat | |
652 void DumperSupport::dump_float(DumpWriter* writer, jfloat f) { | |
653 if (g_isnan(f)) { | |
654 writer->write_u4(0x7fc00000); // collapsing NaNs | |
655 } else { | |
656 union { | |
657 int i; | |
658 float f; | |
659 } u; | |
660 u.f = (float)f; | |
661 writer->write_u4((u4)u.i); | |
662 } | |
663 } | |
664 | |
665 // dump a jdouble | |
666 void DumperSupport::dump_double(DumpWriter* writer, jdouble d) { | |
667 union { | |
668 jlong l; | |
669 double d; | |
670 } u; | |
671 if (g_isnan(d)) { // collapsing NaNs | |
672 u.l = (jlong)(0x7ff80000); | |
673 u.l = (u.l << 32); | |
674 } else { | |
675 u.d = (double)d; | |
676 } | |
677 writer->write_u8((u8)u.l); | |
678 } | |
679 | |
680 // dumps the raw value of the given field | |
681 void DumperSupport::dump_field_value(DumpWriter* writer, char type, address addr) { | |
682 switch (type) { | |
683 case JVM_SIGNATURE_CLASS : | |
684 case JVM_SIGNATURE_ARRAY : { | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
29
diff
changeset
|
685 oop o; |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
29
diff
changeset
|
686 if (UseCompressedOops) { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
29
diff
changeset
|
687 o = oopDesc::load_decode_heap_oop((narrowOop*)addr); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
29
diff
changeset
|
688 } else { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
29
diff
changeset
|
689 o = oopDesc::load_decode_heap_oop((oop*)addr); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
29
diff
changeset
|
690 } |
0 | 691 |
692 // reflection and sun.misc.Unsafe classes may have a reference to a | |
693 // klassOop so filter it out. | |
694 if (o != NULL && o->is_klass()) { | |
695 o = NULL; | |
696 } | |
697 | |
698 // FIXME: When sharing is enabled we don't emit field references to objects | |
699 // in shared spaces. We can remove this once we write records for the classes | |
700 // and strings that are shared. | |
701 if (o != NULL && o->is_shared()) { | |
702 o = NULL; | |
703 } | |
704 writer->write_objectID(o); | |
705 break; | |
706 } | |
707 case JVM_SIGNATURE_BYTE : { | |
708 jbyte* b = (jbyte*)addr; | |
709 writer->write_u1((u1)*b); | |
710 break; | |
711 } | |
712 case JVM_SIGNATURE_CHAR : { | |
713 jchar* c = (jchar*)addr; | |
714 writer->write_u2((u2)*c); | |
715 break; | |
716 } | |
717 case JVM_SIGNATURE_SHORT : { | |
718 jshort* s = (jshort*)addr; | |
719 writer->write_u2((u2)*s); | |
720 break; | |
721 } | |
722 case JVM_SIGNATURE_FLOAT : { | |
723 jfloat* f = (jfloat*)addr; | |
724 dump_float(writer, *f); | |
725 break; | |
726 } | |
727 case JVM_SIGNATURE_DOUBLE : { | |
728 jdouble* f = (jdouble*)addr; | |
729 dump_double(writer, *f); | |
730 break; | |
731 } | |
732 case JVM_SIGNATURE_INT : { | |
733 jint* i = (jint*)addr; | |
734 writer->write_u4((u4)*i); | |
735 break; | |
736 } | |
737 case JVM_SIGNATURE_LONG : { | |
738 jlong* l = (jlong*)addr; | |
739 writer->write_u8((u8)*l); | |
740 break; | |
741 } | |
742 case JVM_SIGNATURE_BOOLEAN : { | |
743 jboolean* b = (jboolean*)addr; | |
744 writer->write_u1((u1)*b); | |
745 break; | |
746 } | |
747 default : ShouldNotReachHere(); | |
748 } | |
749 } | |
750 | |
751 // returns the size of the instance of the given class | |
752 u4 DumperSupport::instance_size(klassOop k) { | |
753 HandleMark hm; | |
754 instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), k); | |
755 | |
756 int size = 0; | |
757 | |
758 for (FieldStream fld(ikh, false, false); !fld.eos(); fld.next()) { | |
759 if (!fld.access_flags().is_static()) { | |
760 symbolOop sig = fld.signature(); | |
761 switch (sig->byte_at(0)) { | |
762 case JVM_SIGNATURE_CLASS : | |
763 case JVM_SIGNATURE_ARRAY : size += oopSize; break; | |
764 | |
765 case JVM_SIGNATURE_BYTE : | |
766 case JVM_SIGNATURE_BOOLEAN : size += 1; break; | |
767 | |
768 case JVM_SIGNATURE_CHAR : | |
769 case JVM_SIGNATURE_SHORT : size += 2; break; | |
770 | |
771 case JVM_SIGNATURE_INT : | |
772 case JVM_SIGNATURE_FLOAT : size += 4; break; | |
773 | |
774 case JVM_SIGNATURE_LONG : | |
775 case JVM_SIGNATURE_DOUBLE : size += 8; break; | |
776 | |
777 default : ShouldNotReachHere(); | |
778 } | |
779 } | |
780 } | |
781 return (u4)size; | |
782 } | |
783 | |
784 // dumps static fields of the given class | |
785 void DumperSupport::dump_static_fields(DumpWriter* writer, klassOop k) { | |
786 HandleMark hm; | |
787 instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), k); | |
788 | |
789 // pass 1 - count the static fields | |
790 u2 field_count = 0; | |
791 for (FieldStream fldc(ikh, true, true); !fldc.eos(); fldc.next()) { | |
792 if (fldc.access_flags().is_static()) field_count++; | |
793 } | |
794 | |
795 writer->write_u2(field_count); | |
796 | |
797 // pass 2 - dump the field descriptors and raw values | |
798 for (FieldStream fld(ikh, true, true); !fld.eos(); fld.next()) { | |
799 if (fld.access_flags().is_static()) { | |
800 symbolOop sig = fld.signature(); | |
801 | |
802 writer->write_objectID(fld.name()); // name | |
803 writer->write_u1(sig2tag(sig)); // type | |
804 | |
805 // value | |
806 int offset = fld.offset(); | |
807 address addr = (address)k + offset; | |
808 | |
809 dump_field_value(writer, sig->byte_at(0), addr); | |
810 } | |
811 } | |
812 } | |
813 | |
814 // dump the raw values of the instance fields of the given object | |
815 void DumperSupport::dump_instance_fields(DumpWriter* writer, oop o) { | |
816 HandleMark hm; | |
817 instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), o->klass()); | |
818 | |
819 for (FieldStream fld(ikh, false, false); !fld.eos(); fld.next()) { | |
820 if (!fld.access_flags().is_static()) { | |
821 symbolOop sig = fld.signature(); | |
822 address addr = (address)o + fld.offset(); | |
823 | |
824 dump_field_value(writer, sig->byte_at(0), addr); | |
825 } | |
826 } | |
827 } | |
828 | |
829 // dumps the definition of the instance fields for a given class | |
830 void DumperSupport::dump_instance_field_descriptors(DumpWriter* writer, klassOop k) { | |
831 HandleMark hm; | |
832 instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), k); | |
833 | |
834 // pass 1 - count the instance fields | |
835 u2 field_count = 0; | |
836 for (FieldStream fldc(ikh, true, true); !fldc.eos(); fldc.next()) { | |
837 if (!fldc.access_flags().is_static()) field_count++; | |
838 } | |
839 | |
840 writer->write_u2(field_count); | |
841 | |
842 // pass 2 - dump the field descriptors | |
843 for (FieldStream fld(ikh, true, true); !fld.eos(); fld.next()) { | |
844 if (!fld.access_flags().is_static()) { | |
845 symbolOop sig = fld.signature(); | |
846 | |
847 writer->write_objectID(fld.name()); // name | |
848 writer->write_u1(sig2tag(sig)); // type | |
849 } | |
850 } | |
851 } | |
852 | |
853 // creates HPROF_GC_INSTANCE_DUMP record for the given object | |
854 void DumperSupport::dump_instance(DumpWriter* writer, oop o) { | |
855 klassOop k = o->klass(); | |
856 | |
857 writer->write_u1(HPROF_GC_INSTANCE_DUMP); | |
858 writer->write_objectID(o); | |
859 writer->write_u4(STACK_TRACE_ID); | |
860 | |
861 // class ID | |
862 writer->write_classID(Klass::cast(k)); | |
863 | |
864 // number of bytes that follow | |
865 writer->write_u4(instance_size(k) ); | |
866 | |
867 // field values | |
868 dump_instance_fields(writer, o); | |
869 } | |
870 | |
871 // creates HPROF_GC_CLASS_DUMP record for the given class and each of | |
872 // its array classes | |
873 void DumperSupport::dump_class_and_array_classes(DumpWriter* writer, klassOop k) { | |
874 Klass* klass = Klass::cast(k); | |
875 assert(klass->oop_is_instance(), "not an instanceKlass"); | |
876 instanceKlass* ik = (instanceKlass*)klass; | |
877 | |
878 writer->write_u1(HPROF_GC_CLASS_DUMP); | |
879 | |
880 // class ID | |
881 writer->write_classID(ik); | |
882 writer->write_u4(STACK_TRACE_ID); | |
883 | |
884 // super class ID | |
885 klassOop java_super = ik->java_super(); | |
886 if (java_super == NULL) { | |
887 writer->write_objectID(NULL); | |
888 } else { | |
889 writer->write_classID(Klass::cast(java_super)); | |
890 } | |
891 | |
892 writer->write_objectID(ik->class_loader()); | |
893 writer->write_objectID(ik->signers()); | |
894 writer->write_objectID(ik->protection_domain()); | |
895 | |
896 // reserved | |
897 writer->write_objectID(NULL); | |
898 writer->write_objectID(NULL); | |
899 | |
900 // instance size | |
901 writer->write_u4(DumperSupport::instance_size(k)); | |
902 | |
903 // size of constant pool - ignored by HAT 1.1 | |
904 writer->write_u2(0); | |
905 | |
906 // number of static fields | |
907 dump_static_fields(writer, k); | |
908 | |
909 // description of instance fields | |
910 dump_instance_field_descriptors(writer, k); | |
911 | |
912 // array classes | |
913 k = klass->array_klass_or_null(); | |
914 while (k != NULL) { | |
915 Klass* klass = Klass::cast(k); | |
916 assert(klass->oop_is_objArray(), "not an objArrayKlass"); | |
917 | |
918 writer->write_u1(HPROF_GC_CLASS_DUMP); | |
919 writer->write_classID(klass); | |
920 writer->write_u4(STACK_TRACE_ID); | |
921 | |
922 // super class of array classes is java.lang.Object | |
923 java_super = klass->java_super(); | |
924 assert(java_super != NULL, "checking"); | |
925 writer->write_classID(Klass::cast(java_super)); | |
926 | |
927 writer->write_objectID(ik->class_loader()); | |
928 writer->write_objectID(ik->signers()); | |
929 writer->write_objectID(ik->protection_domain()); | |
930 | |
931 writer->write_objectID(NULL); // reserved | |
932 writer->write_objectID(NULL); | |
933 writer->write_u4(0); // instance size | |
934 writer->write_u2(0); // constant pool | |
935 writer->write_u2(0); // static fields | |
936 writer->write_u2(0); // instance fields | |
937 | |
938 // get the array class for the next rank | |
939 k = klass->array_klass_or_null(); | |
940 } | |
941 } | |
942 | |
943 // creates HPROF_GC_CLASS_DUMP record for a given primitive array | |
944 // class (and each multi-dimensional array class too) | |
945 void DumperSupport::dump_basic_type_array_class(DumpWriter* writer, klassOop k) { | |
946 // array classes | |
947 while (k != NULL) { | |
948 Klass* klass = Klass::cast(k); | |
949 | |
950 writer->write_u1(HPROF_GC_CLASS_DUMP); | |
951 writer->write_classID(klass); | |
952 writer->write_u4(STACK_TRACE_ID); | |
953 | |
954 // super class of array classes is java.lang.Object | |
955 klassOop java_super = klass->java_super(); | |
956 assert(java_super != NULL, "checking"); | |
957 writer->write_classID(Klass::cast(java_super)); | |
958 | |
959 writer->write_objectID(NULL); // loader | |
960 writer->write_objectID(NULL); // signers | |
961 writer->write_objectID(NULL); // protection domain | |
962 | |
963 writer->write_objectID(NULL); // reserved | |
964 writer->write_objectID(NULL); | |
965 writer->write_u4(0); // instance size | |
966 writer->write_u2(0); // constant pool | |
967 writer->write_u2(0); // static fields | |
968 writer->write_u2(0); // instance fields | |
969 | |
970 // get the array class for the next rank | |
971 k = klass->array_klass_or_null(); | |
972 } | |
973 } | |
974 | |
975 // creates HPROF_GC_OBJ_ARRAY_DUMP record for the given object array | |
976 void DumperSupport::dump_object_array(DumpWriter* writer, objArrayOop array) { | |
977 | |
978 // filter this | |
979 if (array->klass() == Universe::systemObjArrayKlassObj()) return; | |
980 | |
981 writer->write_u1(HPROF_GC_OBJ_ARRAY_DUMP); | |
982 writer->write_objectID(array); | |
983 writer->write_u4(STACK_TRACE_ID); | |
984 writer->write_u4((u4)array->length()); | |
985 | |
986 // array class ID | |
987 writer->write_classID(Klass::cast(array->klass())); | |
988 | |
989 // [id]* elements | |
990 for (int index=0; index<array->length(); index++) { | |
991 oop o = array->obj_at(index); | |
992 writer->write_objectID(o); | |
993 } | |
994 } | |
995 | |
996 #define WRITE_ARRAY(Array, Type, Size) \ | |
997 for (int i=0; i<Array->length(); i++) { writer->write_##Size((Size)array->Type##_at(i)); } | |
998 | |
999 | |
1000 // creates HPROF_GC_PRIM_ARRAY_DUMP record for the given type array | |
1001 void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) { | |
1002 BasicType type = typeArrayKlass::cast(array->klass())->element_type(); | |
1003 | |
1004 writer->write_u1(HPROF_GC_PRIM_ARRAY_DUMP); | |
1005 writer->write_objectID(array); | |
1006 writer->write_u4(STACK_TRACE_ID); | |
1007 writer->write_u4((u4)array->length()); | |
1008 writer->write_u1(type2tag(type)); | |
1009 | |
1010 // nothing to copy | |
1011 if (array->length() == 0) { | |
1012 return; | |
1013 } | |
1014 | |
1015 // If the byte ordering is big endian then we can copy most types directly | |
29
d5fc211aea19
6633953: type2aelembytes{T_ADDRESS} should be 8 bytes in 64 bit VM
kvn
parents:
0
diff
changeset
|
1016 int length_in_bytes = array->length() * type2aelembytes(type); |
0 | 1017 assert(length_in_bytes > 0, "nothing to copy"); |
1018 | |
1019 switch (type) { | |
1020 case T_INT : { | |
1021 if (Bytes::is_Java_byte_ordering_different()) { | |
1022 WRITE_ARRAY(array, int, u4); | |
1023 } else { | |
1024 writer->write_raw((void*)(array->int_at_addr(0)), length_in_bytes); | |
1025 } | |
1026 break; | |
1027 } | |
1028 case T_BYTE : { | |
1029 writer->write_raw((void*)(array->byte_at_addr(0)), length_in_bytes); | |
1030 break; | |
1031 } | |
1032 case T_CHAR : { | |
1033 if (Bytes::is_Java_byte_ordering_different()) { | |
1034 WRITE_ARRAY(array, char, u2); | |
1035 } else { | |
1036 writer->write_raw((void*)(array->char_at_addr(0)), length_in_bytes); | |
1037 } | |
1038 break; | |
1039 } | |
1040 case T_SHORT : { | |
1041 if (Bytes::is_Java_byte_ordering_different()) { | |
1042 WRITE_ARRAY(array, short, u2); | |
1043 } else { | |
1044 writer->write_raw((void*)(array->short_at_addr(0)), length_in_bytes); | |
1045 } | |
1046 break; | |
1047 } | |
1048 case T_BOOLEAN : { | |
1049 if (Bytes::is_Java_byte_ordering_different()) { | |
1050 WRITE_ARRAY(array, bool, u1); | |
1051 } else { | |
1052 writer->write_raw((void*)(array->bool_at_addr(0)), length_in_bytes); | |
1053 } | |
1054 break; | |
1055 } | |
1056 case T_LONG : { | |
1057 if (Bytes::is_Java_byte_ordering_different()) { | |
1058 WRITE_ARRAY(array, long, u8); | |
1059 } else { | |
1060 writer->write_raw((void*)(array->long_at_addr(0)), length_in_bytes); | |
1061 } | |
1062 break; | |
1063 } | |
1064 | |
1065 // handle float/doubles in a special value to ensure than NaNs are | |
1066 // written correctly. TO DO: Check if we can avoid this on processors that | |
1067 // use IEEE 754. | |
1068 | |
1069 case T_FLOAT : { | |
1070 for (int i=0; i<array->length(); i++) { | |
1071 dump_float( writer, array->float_at(i) ); | |
1072 } | |
1073 break; | |
1074 } | |
1075 case T_DOUBLE : { | |
1076 for (int i=0; i<array->length(); i++) { | |
1077 dump_double( writer, array->double_at(i) ); | |
1078 } | |
1079 break; | |
1080 } | |
1081 default : ShouldNotReachHere(); | |
1082 } | |
1083 } | |
1084 | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1085 // create a HPROF_FRAME record of the given methodOop and bci |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1086 void DumperSupport::dump_stack_frame(DumpWriter* writer, |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1087 int frame_serial_num, |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1088 int class_serial_num, |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1089 methodOop m, |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1090 int bci) { |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1091 int line_number; |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1092 if (m->is_native()) { |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1093 line_number = -3; // native frame |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1094 } else { |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1095 line_number = m->line_number_from_bci(bci); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1096 } |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1097 |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1098 write_header(writer, HPROF_FRAME, 4*oopSize + 2*sizeof(u4)); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1099 writer->write_id(frame_serial_num); // frame serial number |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1100 writer->write_objectID(m->name()); // method's name |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1101 writer->write_objectID(m->signature()); // method's signature |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1102 |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1103 assert(Klass::cast(m->method_holder())->oop_is_instance(), "not instanceKlass"); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1104 writer->write_objectID(instanceKlass::cast(m->method_holder())->source_file_name()); // source file name |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1105 writer->write_u4(class_serial_num); // class serial number |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1106 writer->write_u4((u4) line_number); // line number |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1107 } |
0 | 1108 |
1109 // Support class used to generate HPROF_UTF8 records from the entries in the | |
1110 // SymbolTable. | |
1111 | |
1112 class SymbolTableDumper : public OopClosure { | |
1113 private: | |
1114 DumpWriter* _writer; | |
1115 DumpWriter* writer() const { return _writer; } | |
1116 public: | |
1117 SymbolTableDumper(DumpWriter* writer) { _writer = writer; } | |
1118 void do_oop(oop* obj_p); | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
29
diff
changeset
|
1119 void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); } |
0 | 1120 }; |
1121 | |
1122 void SymbolTableDumper::do_oop(oop* obj_p) { | |
1123 ResourceMark rm; | |
1124 symbolOop sym = (symbolOop)*obj_p; | |
1125 | |
1126 int len = sym->utf8_length(); | |
1127 if (len > 0) { | |
1128 char* s = sym->as_utf8(); | |
1129 DumperSupport::write_header(writer(), HPROF_UTF8, oopSize + len); | |
1130 writer()->write_objectID(sym); | |
1131 writer()->write_raw(s, len); | |
1132 } | |
1133 } | |
1134 | |
1135 | |
1136 // Support class used to generate HPROF_GC_ROOT_JNI_LOCAL records | |
1137 | |
1138 class JNILocalsDumper : public OopClosure { | |
1139 private: | |
1140 DumpWriter* _writer; | |
1141 u4 _thread_serial_num; | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1142 int _frame_num; |
0 | 1143 DumpWriter* writer() const { return _writer; } |
1144 public: | |
1145 JNILocalsDumper(DumpWriter* writer, u4 thread_serial_num) { | |
1146 _writer = writer; | |
1147 _thread_serial_num = thread_serial_num; | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1148 _frame_num = -1; // default - empty stack |
0 | 1149 } |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1150 void set_frame_number(int n) { _frame_num = n; } |
0 | 1151 void do_oop(oop* obj_p); |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
29
diff
changeset
|
1152 void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); } |
0 | 1153 }; |
1154 | |
1155 | |
1156 void JNILocalsDumper::do_oop(oop* obj_p) { | |
1157 // ignore null or deleted handles | |
1158 oop o = *obj_p; | |
1159 if (o != NULL && o != JNIHandles::deleted_handle()) { | |
1160 writer()->write_u1(HPROF_GC_ROOT_JNI_LOCAL); | |
1161 writer()->write_objectID(o); | |
1162 writer()->write_u4(_thread_serial_num); | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1163 writer()->write_u4((u4)_frame_num); |
0 | 1164 } |
1165 } | |
1166 | |
1167 | |
1168 // Support class used to generate HPROF_GC_ROOT_JNI_GLOBAL records | |
1169 | |
1170 class JNIGlobalsDumper : public OopClosure { | |
1171 private: | |
1172 DumpWriter* _writer; | |
1173 DumpWriter* writer() const { return _writer; } | |
1174 | |
1175 public: | |
1176 JNIGlobalsDumper(DumpWriter* writer) { | |
1177 _writer = writer; | |
1178 } | |
1179 void do_oop(oop* obj_p); | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
29
diff
changeset
|
1180 void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); } |
0 | 1181 }; |
1182 | |
1183 void JNIGlobalsDumper::do_oop(oop* obj_p) { | |
1184 oop o = *obj_p; | |
1185 | |
1186 // ignore these | |
1187 if (o == NULL || o == JNIHandles::deleted_handle()) return; | |
1188 | |
1189 // we ignore global ref to symbols and other internal objects | |
1190 if (o->is_instance() || o->is_objArray() || o->is_typeArray()) { | |
1191 writer()->write_u1(HPROF_GC_ROOT_JNI_GLOBAL); | |
1192 writer()->write_objectID(o); | |
1193 writer()->write_objectID((oopDesc*)obj_p); // global ref ID | |
1194 } | |
1195 }; | |
1196 | |
1197 | |
1198 // Support class used to generate HPROF_GC_ROOT_MONITOR_USED records | |
1199 | |
1200 class MonitorUsedDumper : public OopClosure { | |
1201 private: | |
1202 DumpWriter* _writer; | |
1203 DumpWriter* writer() const { return _writer; } | |
1204 public: | |
1205 MonitorUsedDumper(DumpWriter* writer) { | |
1206 _writer = writer; | |
1207 } | |
1208 void do_oop(oop* obj_p) { | |
1209 writer()->write_u1(HPROF_GC_ROOT_MONITOR_USED); | |
1210 writer()->write_objectID(*obj_p); | |
1211 } | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
29
diff
changeset
|
1212 void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); } |
0 | 1213 }; |
1214 | |
1215 | |
1216 // Support class used to generate HPROF_GC_ROOT_STICKY_CLASS records | |
1217 | |
1218 class StickyClassDumper : public OopClosure { | |
1219 private: | |
1220 DumpWriter* _writer; | |
1221 DumpWriter* writer() const { return _writer; } | |
1222 public: | |
1223 StickyClassDumper(DumpWriter* writer) { | |
1224 _writer = writer; | |
1225 } | |
1226 void do_oop(oop* obj_p); | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
29
diff
changeset
|
1227 void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); } |
0 | 1228 }; |
1229 | |
1230 void StickyClassDumper::do_oop(oop* obj_p) { | |
1231 if (*obj_p != NULL) { | |
1232 oop o = *obj_p; | |
1233 if (o->is_klass()) { | |
1234 klassOop k = klassOop(o); | |
1235 if (Klass::cast(k)->oop_is_instance()) { | |
1236 instanceKlass* ik = instanceKlass::cast(k); | |
1237 writer()->write_u1(HPROF_GC_ROOT_STICKY_CLASS); | |
1238 writer()->write_classID(ik); | |
1239 } | |
1240 } | |
1241 } | |
1242 } | |
1243 | |
1244 | |
1245 class VM_HeapDumper; | |
1246 | |
1247 // Support class using when iterating over the heap. | |
1248 | |
1249 class HeapObjectDumper : public ObjectClosure { | |
1250 private: | |
1251 VM_HeapDumper* _dumper; | |
1252 DumpWriter* _writer; | |
1253 | |
1254 VM_HeapDumper* dumper() { return _dumper; } | |
1255 DumpWriter* writer() { return _writer; } | |
1256 | |
1257 // used to indicate that a record has been writen | |
1258 void mark_end_of_record(); | |
1259 | |
1260 public: | |
1261 HeapObjectDumper(VM_HeapDumper* dumper, DumpWriter* writer) { | |
1262 _dumper = dumper; | |
1263 _writer = writer; | |
1264 } | |
1265 | |
1266 // called for each object in the heap | |
1267 void do_object(oop o); | |
1268 }; | |
1269 | |
1270 void HeapObjectDumper::do_object(oop o) { | |
1271 // hide the sentinel for deleted handles | |
1272 if (o == JNIHandles::deleted_handle()) return; | |
1273 | |
1274 // ignore KlassKlass objects | |
1275 if (o->is_klass()) return; | |
1276 | |
1277 // skip classes as these emitted as HPROF_GC_CLASS_DUMP records | |
1278 if (o->klass() == SystemDictionary::class_klass()) { | |
1279 if (!java_lang_Class::is_primitive(o)) { | |
1280 return; | |
1281 } | |
1282 } | |
1283 | |
1284 // create a HPROF_GC_INSTANCE record for each object | |
1285 if (o->is_instance()) { | |
1286 DumperSupport::dump_instance(writer(), o); | |
1287 mark_end_of_record(); | |
1288 } else { | |
1289 // create a HPROF_GC_OBJ_ARRAY_DUMP record for each object array | |
1290 if (o->is_objArray()) { | |
1291 DumperSupport::dump_object_array(writer(), objArrayOop(o)); | |
1292 mark_end_of_record(); | |
1293 } else { | |
1294 // create a HPROF_GC_PRIM_ARRAY_DUMP record for each type array | |
1295 if (o->is_typeArray()) { | |
1296 DumperSupport::dump_prim_array(writer(), typeArrayOop(o)); | |
1297 mark_end_of_record(); | |
1298 } | |
1299 } | |
1300 } | |
1301 } | |
1302 | |
1303 // The VM operation that performs the heap dump | |
1304 class VM_HeapDumper : public VM_GC_Operation { | |
1305 private: | |
1306 DumpWriter* _writer; | |
1307 bool _gc_before_heap_dump; | |
1308 bool _is_segmented_dump; | |
1309 jlong _dump_start; | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1310 GrowableArray<Klass*>* _klass_map; |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1311 ThreadStackTrace** _stack_traces; |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1312 int _num_threads; |
0 | 1313 |
1314 // accessors | |
1315 DumpWriter* writer() const { return _writer; } | |
1316 bool is_segmented_dump() const { return _is_segmented_dump; } | |
1317 void set_segmented_dump() { _is_segmented_dump = true; } | |
1318 jlong dump_start() const { return _dump_start; } | |
1319 void set_dump_start(jlong pos); | |
1320 | |
1321 bool skip_operation() const; | |
1322 | |
1323 // writes a HPROF_LOAD_CLASS record | |
1324 static void do_load_class(klassOop k); | |
1325 | |
1326 // writes a HPROF_GC_CLASS_DUMP record for the given class | |
1327 // (and each array class too) | |
1328 static void do_class_dump(klassOop k); | |
1329 | |
1330 // writes a HPROF_GC_CLASS_DUMP records for a given basic type | |
1331 // array (and each multi-dimensional array too) | |
1332 static void do_basic_type_array_class_dump(klassOop k); | |
1333 | |
1334 // HPROF_GC_ROOT_THREAD_OBJ records | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1335 int do_thread(JavaThread* thread, u4 thread_serial_num); |
0 | 1336 void do_threads(); |
1337 | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1338 void add_class_serial_number(Klass* k, int serial_num) { |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1339 _klass_map->at_put_grow(serial_num, k); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1340 } |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1341 |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1342 // HPROF_TRACE and HPROF_FRAME records |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1343 void dump_stack_traces(); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1344 |
0 | 1345 // writes a HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT record |
1346 void write_dump_header(); | |
1347 | |
1348 // fixes up the length of the current dump record | |
1349 void write_current_dump_record_length(); | |
1350 | |
1351 // fixes up the current dump record )and writes HPROF_HEAP_DUMP_END | |
1352 // record in the case of a segmented heap dump) | |
1353 void end_of_dump(); | |
1354 | |
1355 public: | |
1356 VM_HeapDumper(DumpWriter* writer, bool gc_before_heap_dump) : | |
1357 VM_GC_Operation(0 /* total collections, dummy, ignored */, | |
1358 0 /* total full collections, dummy, ignored */, | |
1359 gc_before_heap_dump) { | |
1360 _writer = writer; | |
1361 _gc_before_heap_dump = gc_before_heap_dump; | |
1362 _is_segmented_dump = false; | |
1363 _dump_start = (jlong)-1; | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1364 _klass_map = new (ResourceObj::C_HEAP) GrowableArray<Klass*>(INITIAL_CLASS_COUNT, true); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1365 _stack_traces = NULL; |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1366 _num_threads = 0; |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1367 } |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1368 ~VM_HeapDumper() { |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1369 if (_stack_traces != NULL) { |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1370 for (int i=0; i < _num_threads; i++) { |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1371 delete _stack_traces[i]; |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1372 } |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1373 FREE_C_HEAP_ARRAY(ThreadStackTrace*, _stack_traces); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1374 } |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1375 delete _klass_map; |
0 | 1376 } |
1377 | |
1378 VMOp_Type type() const { return VMOp_HeapDumper; } | |
1379 // used to mark sub-record boundary | |
1380 void check_segment_length(); | |
1381 void doit(); | |
1382 }; | |
1383 | |
1384 bool VM_HeapDumper::skip_operation() const { | |
1385 return false; | |
1386 } | |
1387 | |
1388 // sets the dump starting position | |
1389 void VM_HeapDumper::set_dump_start(jlong pos) { | |
1390 _dump_start = pos; | |
1391 } | |
1392 | |
1393 // writes a HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT record | |
1394 void VM_HeapDumper::write_dump_header() { | |
1395 if (writer()->is_open()) { | |
1396 if (is_segmented_dump()) { | |
1397 writer()->write_u1(HPROF_HEAP_DUMP_SEGMENT); | |
1398 } else { | |
1399 writer()->write_u1(HPROF_HEAP_DUMP); | |
1400 } | |
1401 writer()->write_u4(0); // current ticks | |
1402 | |
1403 // record the starting position for the dump (its length will be fixed up later) | |
1404 set_dump_start(writer()->current_offset()); | |
1405 writer()->write_u4(0); | |
1406 } | |
1407 } | |
1408 | |
1409 // fixes up the length of the current dump record | |
1410 void VM_HeapDumper::write_current_dump_record_length() { | |
1411 if (writer()->is_open()) { | |
1412 assert(dump_start() >= 0, "no dump start recorded"); | |
1413 | |
1414 // calculate the size of the dump record | |
1415 jlong dump_end = writer()->current_offset(); | |
1416 jlong dump_len = (dump_end - dump_start() - 4); | |
1417 | |
1418 // record length must fit in a u4 | |
1419 if (dump_len > (jlong)(4L*(jlong)G)) { | |
1420 warning("record is too large"); | |
1421 } | |
1422 | |
1423 // seek to the dump start and fix-up the length | |
1424 writer()->seek_to_offset(dump_start()); | |
1425 writer()->write_u4((u4)dump_len); | |
1426 | |
1427 // adjust the total size written to keep the bytes written correct. | |
1428 writer()->adjust_bytes_written(-((long) sizeof(u4))); | |
1429 | |
1430 // seek to dump end so we can continue | |
1431 writer()->seek_to_offset(dump_end); | |
1432 | |
1433 // no current dump record | |
1434 set_dump_start((jlong)-1); | |
1435 } | |
1436 } | |
1437 | |
1438 // used on a sub-record boundary to check if we need to start a | |
1439 // new segment. | |
1440 void VM_HeapDumper::check_segment_length() { | |
1441 if (writer()->is_open()) { | |
1442 if (is_segmented_dump()) { | |
1443 // don't use current_offset that would be too expensive on a per record basis | |
1444 jlong dump_end = writer()->bytes_written() + writer()->bytes_unwritten(); | |
1445 assert(dump_end == writer()->current_offset(), "checking"); | |
1446 jlong dump_len = (dump_end - dump_start() - 4); | |
1447 assert(dump_len >= 0 && dump_len <= max_juint, "bad dump length"); | |
1448 | |
1449 if (dump_len > (jlong)HeapDumpSegmentSize) { | |
1450 write_current_dump_record_length(); | |
1451 write_dump_header(); | |
1452 } | |
1453 } | |
1454 } | |
1455 } | |
1456 | |
1457 // fixes up the current dump record )and writes HPROF_HEAP_DUMP_END | |
1458 // record in the case of a segmented heap dump) | |
1459 void VM_HeapDumper::end_of_dump() { | |
1460 if (writer()->is_open()) { | |
1461 write_current_dump_record_length(); | |
1462 | |
1463 // for segmented dump we write the end record | |
1464 if (is_segmented_dump()) { | |
1465 writer()->write_u1(HPROF_HEAP_DUMP_END); | |
1466 writer()->write_u4(0); | |
1467 writer()->write_u4(0); | |
1468 } | |
1469 } | |
1470 } | |
1471 | |
1472 // marks sub-record boundary | |
1473 void HeapObjectDumper::mark_end_of_record() { | |
1474 dumper()->check_segment_length(); | |
1475 } | |
1476 | |
1477 // writes a HPROF_LOAD_CLASS record for the class (and each of its | |
1478 // array classes) | |
1479 void VM_HeapDumper::do_load_class(klassOop k) { | |
1480 static u4 class_serial_num = 0; | |
1481 | |
1482 VM_HeapDumper* dumper = ((VM_HeapDumper*)VMThread::vm_operation()); | |
1483 DumpWriter* writer = dumper->writer(); | |
1484 | |
1485 // len of HPROF_LOAD_CLASS record | |
1486 u4 remaining = 2*oopSize + 2*sizeof(u4); | |
1487 | |
1488 // write a HPROF_LOAD_CLASS for the class and each array class | |
1489 do { | |
1490 DumperSupport::write_header(writer, HPROF_LOAD_CLASS, remaining); | |
1491 | |
1492 // class serial number is just a number | |
1493 writer->write_u4(++class_serial_num); | |
1494 | |
1495 // class ID | |
1496 Klass* klass = Klass::cast(k); | |
1497 writer->write_classID(klass); | |
1498 | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1499 // add the klassOop and class serial number pair |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1500 dumper->add_class_serial_number(klass, class_serial_num); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1501 |
0 | 1502 writer->write_u4(STACK_TRACE_ID); |
1503 | |
1504 // class name ID | |
1505 symbolOop name = klass->name(); | |
1506 writer->write_objectID(name); | |
1507 | |
1508 // write a LOAD_CLASS record for the array type (if it exists) | |
1509 k = klass->array_klass_or_null(); | |
1510 } while (k != NULL); | |
1511 } | |
1512 | |
1513 // writes a HPROF_GC_CLASS_DUMP record for the given class | |
1514 void VM_HeapDumper::do_class_dump(klassOop k) { | |
1515 VM_HeapDumper* dumper = ((VM_HeapDumper*)VMThread::vm_operation()); | |
1516 DumpWriter* writer = dumper->writer(); | |
1517 DumperSupport::dump_class_and_array_classes(writer, k); | |
1518 } | |
1519 | |
1520 // writes a HPROF_GC_CLASS_DUMP records for a given basic type | |
1521 // array (and each multi-dimensional array too) | |
1522 void VM_HeapDumper::do_basic_type_array_class_dump(klassOop k) { | |
1523 VM_HeapDumper* dumper = ((VM_HeapDumper*)VMThread::vm_operation()); | |
1524 DumpWriter* writer = dumper->writer(); | |
1525 DumperSupport::dump_basic_type_array_class(writer, k); | |
1526 } | |
1527 | |
1528 // Walk the stack of the given thread. | |
1529 // Dumps a HPROF_GC_ROOT_JAVA_FRAME record for each local | |
1530 // Dumps a HPROF_GC_ROOT_JNI_LOCAL record for each JNI local | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1531 // |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1532 // It returns the number of Java frames in this thread stack |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1533 int VM_HeapDumper::do_thread(JavaThread* java_thread, u4 thread_serial_num) { |
0 | 1534 JNILocalsDumper blk(writer(), thread_serial_num); |
1535 | |
1536 oop threadObj = java_thread->threadObj(); | |
1537 assert(threadObj != NULL, "sanity check"); | |
1538 | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1539 int stack_depth = 0; |
0 | 1540 if (java_thread->has_last_Java_frame()) { |
1541 | |
1542 // vframes are resource allocated | |
1543 Thread* current_thread = Thread::current(); | |
1544 ResourceMark rm(current_thread); | |
1545 HandleMark hm(current_thread); | |
1546 | |
1547 RegisterMap reg_map(java_thread); | |
1548 frame f = java_thread->last_frame(); | |
1549 vframe* vf = vframe::new_vframe(&f, ®_map, java_thread); | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1550 frame* last_entry_frame = NULL; |
0 | 1551 |
1552 while (vf != NULL) { | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1553 blk.set_frame_number(stack_depth); |
0 | 1554 if (vf->is_java_frame()) { |
1555 | |
1556 // java frame (interpreted, compiled, ...) | |
1557 javaVFrame *jvf = javaVFrame::cast(vf); | |
1558 if (!(jvf->method()->is_native())) { | |
1559 StackValueCollection* locals = jvf->locals(); | |
1560 for (int slot=0; slot<locals->size(); slot++) { | |
1561 if (locals->at(slot)->type() == T_OBJECT) { | |
1562 oop o = locals->obj_at(slot)(); | |
1563 | |
1564 if (o != NULL) { | |
1565 writer()->write_u1(HPROF_GC_ROOT_JAVA_FRAME); | |
1566 writer()->write_objectID(o); | |
1567 writer()->write_u4(thread_serial_num); | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1568 writer()->write_u4((u4) stack_depth); |
0 | 1569 } |
1570 } | |
1571 } | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1572 } else { |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1573 // native frame |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1574 if (stack_depth == 0) { |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1575 // JNI locals for the top frame. |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1576 java_thread->active_handles()->oops_do(&blk); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1577 } else { |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1578 if (last_entry_frame != NULL) { |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1579 // JNI locals for the entry frame |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1580 assert(last_entry_frame->is_entry_frame(), "checking"); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1581 last_entry_frame->entry_frame_call_wrapper()->handles()->oops_do(&blk); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1582 } |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1583 } |
0 | 1584 } |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1585 // increment only for Java frames |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1586 stack_depth++; |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1587 last_entry_frame = NULL; |
0 | 1588 |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1589 } else { |
0 | 1590 // externalVFrame - if it's an entry frame then report any JNI locals |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1591 // as roots when we find the corresponding native javaVFrame |
0 | 1592 frame* fr = vf->frame_pointer(); |
1593 assert(fr != NULL, "sanity check"); | |
1594 if (fr->is_entry_frame()) { | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1595 last_entry_frame = fr; |
0 | 1596 } |
1597 } | |
1598 vf = vf->sender(); | |
1599 } | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1600 } else { |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1601 // no last java frame but there may be JNI locals |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1602 java_thread->active_handles()->oops_do(&blk); |
0 | 1603 } |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1604 return stack_depth; |
0 | 1605 } |
1606 | |
1607 | |
1608 // write a HPROF_GC_ROOT_THREAD_OBJ record for each java thread. Then walk | |
1609 // the stack so that locals and JNI locals are dumped. | |
1610 void VM_HeapDumper::do_threads() { | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1611 for (int i=0; i < _num_threads; i++) { |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1612 JavaThread* thread = _stack_traces[i]->thread(); |
0 | 1613 oop threadObj = thread->threadObj(); |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1614 u4 thread_serial_num = i+1; |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1615 u4 stack_serial_num = thread_serial_num + STACK_TRACE_ID; |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1616 writer()->write_u1(HPROF_GC_ROOT_THREAD_OBJ); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1617 writer()->write_objectID(threadObj); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1618 writer()->write_u4(thread_serial_num); // thread number |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1619 writer()->write_u4(stack_serial_num); // stack trace serial number |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1620 int num_frames = do_thread(thread, thread_serial_num); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1621 assert(num_frames == _stack_traces[i]->get_stack_depth(), |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1622 "total number of Java frames not matched"); |
0 | 1623 } |
1624 } | |
1625 | |
1626 | |
1627 // The VM operation that dumps the heap. The dump consists of the following | |
1628 // records: | |
1629 // | |
1630 // HPROF_HEADER | |
1631 // [HPROF_UTF8]* | |
1632 // [HPROF_LOAD_CLASS]* | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1633 // [[HPROF_FRAME]*|HPROF_TRACE]* |
0 | 1634 // [HPROF_GC_CLASS_DUMP]* |
1635 // HPROF_HEAP_DUMP | |
1636 // | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1637 // The HPROF_TRACE records represent the stack traces where the heap dump |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1638 // is generated and a "dummy trace" record which does not include |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1639 // any frames. The dummy trace record is used to be referenced as the |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1640 // unknown object alloc site. |
0 | 1641 // |
1642 // The HPROF_HEAP_DUMP record has a length following by sub-records. To allow | |
1643 // the heap dump be generated in a single pass we remember the position of | |
1644 // the dump length and fix it up after all sub-records have been written. | |
1645 // To generate the sub-records we iterate over the heap, writing | |
1646 // HPROF_GC_INSTANCE_DUMP, HPROF_GC_OBJ_ARRAY_DUMP, and HPROF_GC_PRIM_ARRAY_DUMP | |
1647 // records as we go. Once that is done we write records for some of the GC | |
1648 // roots. | |
1649 | |
1650 void VM_HeapDumper::doit() { | |
1651 | |
1652 HandleMark hm; | |
1653 CollectedHeap* ch = Universe::heap(); | |
1654 if (_gc_before_heap_dump) { | |
1655 ch->collect_as_vm_thread(GCCause::_heap_dump); | |
1656 } else { | |
1657 // make the heap parsable (no need to retire TLABs) | |
1658 ch->ensure_parsability(false); | |
1659 } | |
1660 | |
1661 // Write the file header - use 1.0.2 for large heaps, otherwise 1.0.1 | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
1662 size_t used = ch->used(); |
0 | 1663 const char* header; |
1664 if (used > (size_t)SegmentedHeapDumpThreshold) { | |
1665 set_segmented_dump(); | |
1666 header = "JAVA PROFILE 1.0.2"; | |
1667 } else { | |
1668 header = "JAVA PROFILE 1.0.1"; | |
1669 } | |
1670 // header is few bytes long - no chance to overflow int | |
1671 writer()->write_raw((void*)header, (int)strlen(header)); | |
1672 writer()->write_u1(0); // terminator | |
1673 writer()->write_u4(oopSize); | |
1674 writer()->write_u8(os::javaTimeMillis()); | |
1675 | |
1676 // HPROF_UTF8 records | |
1677 SymbolTableDumper sym_dumper(writer()); | |
1678 SymbolTable::oops_do(&sym_dumper); | |
1679 | |
1680 // write HPROF_LOAD_CLASS records | |
1681 SystemDictionary::classes_do(&do_load_class); | |
1682 Universe::basic_type_classes_do(&do_load_class); | |
1683 | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1684 // write HPROF_FRAME and HPROF_TRACE records |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1685 // this must be called after _klass_map is built when iterating the classes above. |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1686 dump_stack_traces(); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1687 |
0 | 1688 // write HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT |
1689 write_dump_header(); | |
1690 | |
1691 // Writes HPROF_GC_CLASS_DUMP records | |
1692 SystemDictionary::classes_do(&do_class_dump); | |
1693 Universe::basic_type_classes_do(&do_basic_type_array_class_dump); | |
1694 check_segment_length(); | |
1695 | |
1696 // writes HPROF_GC_INSTANCE_DUMP records. | |
1697 // After each sub-record is written check_segment_length will be invoked. When | |
1698 // generated a segmented heap dump this allows us to check if the current | |
1699 // segment exceeds a threshold and if so, then a new segment is started. | |
1700 // The HPROF_GC_CLASS_DUMP and HPROF_GC_INSTANCE_DUMP are the vast bulk | |
1701 // of the heap dump. | |
1702 HeapObjectDumper obj_dumper(this, writer()); | |
1703 Universe::heap()->object_iterate(&obj_dumper); | |
1704 | |
1705 // HPROF_GC_ROOT_THREAD_OBJ + frames + jni locals | |
1706 do_threads(); | |
1707 check_segment_length(); | |
1708 | |
1709 // HPROF_GC_ROOT_MONITOR_USED | |
1710 MonitorUsedDumper mon_dumper(writer()); | |
1711 ObjectSynchronizer::oops_do(&mon_dumper); | |
1712 check_segment_length(); | |
1713 | |
1714 // HPROF_GC_ROOT_JNI_GLOBAL | |
1715 JNIGlobalsDumper jni_dumper(writer()); | |
1716 JNIHandles::oops_do(&jni_dumper); | |
1717 check_segment_length(); | |
1718 | |
1719 // HPROF_GC_ROOT_STICKY_CLASS | |
1720 StickyClassDumper class_dumper(writer()); | |
1721 SystemDictionary::always_strong_oops_do(&class_dumper); | |
1722 | |
1723 // fixes up the length of the dump record. In the case of a segmented | |
1724 // heap then the HPROF_HEAP_DUMP_END record is also written. | |
1725 end_of_dump(); | |
1726 } | |
1727 | |
396
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1728 void VM_HeapDumper::dump_stack_traces() { |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1729 // write a HPROF_TRACE record without any frames to be referenced as object alloc sites |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1730 DumperSupport::write_header(writer(), HPROF_TRACE, 3*sizeof(u4)); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1731 writer()->write_u4((u4) STACK_TRACE_ID); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1732 writer()->write_u4(0); // thread number |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1733 writer()->write_u4(0); // frame count |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1734 |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1735 _stack_traces = NEW_C_HEAP_ARRAY(ThreadStackTrace*, Threads::number_of_threads()); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1736 int frame_serial_num = 0; |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1737 for (JavaThread* thread = Threads::first(); thread != NULL ; thread = thread->next()) { |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1738 oop threadObj = thread->threadObj(); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1739 if (threadObj != NULL && !thread->is_exiting() && !thread->is_hidden_from_external_view()) { |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1740 // dump thread stack trace |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1741 ThreadStackTrace* stack_trace = new ThreadStackTrace(thread, false); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1742 stack_trace->dump_stack_at_safepoint(-1); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1743 _stack_traces[_num_threads++] = stack_trace; |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1744 |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1745 // write HPROF_FRAME records for this thread's stack trace |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1746 int depth = stack_trace->get_stack_depth(); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1747 int thread_frame_start = frame_serial_num; |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1748 for (int j=0; j < depth; j++) { |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1749 StackFrameInfo* frame = stack_trace->stack_frame_at(j); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1750 methodOop m = frame->method(); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1751 int class_serial_num = _klass_map->find(Klass::cast(m->method_holder())); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1752 // the class serial number starts from 1 |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1753 assert(class_serial_num > 0, "class not found"); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1754 DumperSupport::dump_stack_frame(writer(), ++frame_serial_num, class_serial_num, m, frame->bci()); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1755 } |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1756 |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1757 // write HPROF_TRACE record for one thread |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1758 DumperSupport::write_header(writer(), HPROF_TRACE, 3*sizeof(u4) + depth*oopSize); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1759 int stack_serial_num = _num_threads + STACK_TRACE_ID; |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1760 writer()->write_u4(stack_serial_num); // stack trace serial number |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1761 writer()->write_u4((u4) _num_threads); // thread serial number |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1762 writer()->write_u4(depth); // frame count |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1763 for (int j=1; j <= depth; j++) { |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1764 writer()->write_id(thread_frame_start + j); |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1765 } |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1766 } |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1767 } |
4d05b7cb7842
6306922: Dump dump created by +HeapDumpOnOutOfMemoryError should include stack traces for stack roots
mchung
parents:
356
diff
changeset
|
1768 } |
0 | 1769 |
1770 // dump the heap to given path. | |
1771 int HeapDumper::dump(const char* path) { | |
1772 assert(path != NULL && strlen(path) > 0, "path missing"); | |
1773 | |
1774 // print message in interactive case | |
1775 if (print_to_tty()) { | |
1776 tty->print_cr("Dumping heap to %s ...", path); | |
1777 timer()->start(); | |
1778 } | |
1779 | |
1780 // create the dump writer. If the file can be opened then bail | |
1781 DumpWriter writer(path); | |
1782 if (!writer.is_open()) { | |
1783 set_error(writer.error()); | |
1784 if (print_to_tty()) { | |
1785 tty->print_cr("Unable to create %s: %s", path, | |
1786 (error() != NULL) ? error() : "reason unknown"); | |
1787 } | |
1788 return -1; | |
1789 } | |
1790 | |
1791 // generate the dump | |
1792 VM_HeapDumper dumper(&writer, _gc_before_heap_dump); | |
1793 VMThread::execute(&dumper); | |
1794 | |
1795 // close dump file and record any error that the writer may have encountered | |
1796 writer.close(); | |
1797 set_error(writer.error()); | |
1798 | |
1799 // print message in interactive case | |
1800 if (print_to_tty()) { | |
1801 timer()->stop(); | |
1802 if (error() == NULL) { | |
1803 char msg[256]; | |
1804 sprintf(msg, "Heap dump file created [%s bytes in %3.3f secs]", | |
1805 os::jlong_format_specifier(), timer()->seconds()); | |
1806 tty->print_cr(msg, writer.bytes_written()); | |
1807 } else { | |
1808 tty->print_cr("Dump file is incomplete: %s", writer.error()); | |
1809 } | |
1810 } | |
1811 | |
1812 return (writer.error() == NULL) ? 0 : -1; | |
1813 } | |
1814 | |
1815 // stop timer (if still active), and free any error string we might be holding | |
1816 HeapDumper::~HeapDumper() { | |
1817 if (timer()->is_active()) { | |
1818 timer()->stop(); | |
1819 } | |
1820 set_error(NULL); | |
1821 } | |
1822 | |
1823 | |
1824 // returns the error string (resource allocated), or NULL | |
1825 char* HeapDumper::error_as_C_string() const { | |
1826 if (error() != NULL) { | |
1827 char* str = NEW_RESOURCE_ARRAY(char, strlen(error())+1); | |
1828 strcpy(str, error()); | |
1829 return str; | |
1830 } else { | |
1831 return NULL; | |
1832 } | |
1833 } | |
1834 | |
1835 // set the error string | |
1836 void HeapDumper::set_error(char* error) { | |
1837 if (_error != NULL) { | |
1838 os::free(_error); | |
1839 } | |
1840 if (error == NULL) { | |
1841 _error = NULL; | |
1842 } else { | |
1843 _error = os::strdup(error); | |
1844 assert(_error != NULL, "allocation failure"); | |
1845 } | |
1846 } | |
1847 | |
1848 | |
1849 // Called by error reporting | |
1850 void HeapDumper::dump_heap() { | |
1851 static char path[JVM_MAXPATHLEN]; | |
1852 | |
1853 // The dump file defaults to java_pid<pid>.hprof in the current working | |
1854 // directory. HeapDumpPath=<file> can be used to specify an alternative | |
1855 // dump file name or a directory where dump file is created. | |
1856 bool use_default_filename = true; | |
1857 if (HeapDumpPath == NULL || HeapDumpPath[0] == '\0') { | |
1858 path[0] = '\0'; // HeapDumpPath=<file> not specified | |
1859 } else { | |
1860 assert(strlen(HeapDumpPath) < sizeof(path), "HeapDumpPath too long"); | |
1861 strcpy(path, HeapDumpPath); | |
1862 // check if the path is a directory (must exist) | |
1863 DIR* dir = os::opendir(path); | |
1864 if (dir == NULL) { | |
1865 use_default_filename = false; | |
1866 } else { | |
1867 // HeapDumpPath specified a directory. We append a file separator | |
1868 // (if needed). | |
1869 os::closedir(dir); | |
1870 size_t fs_len = strlen(os::file_separator()); | |
1871 if (strlen(path) >= fs_len) { | |
1872 char* end = path; | |
1873 end += (strlen(path) - fs_len); | |
1874 if (strcmp(end, os::file_separator()) != 0) { | |
1875 assert(strlen(path) + strlen(os::file_separator()) < sizeof(path), | |
1876 "HeapDumpPath too long"); | |
1877 strcat(path, os::file_separator()); | |
1878 } | |
1879 } | |
1880 } | |
1881 } | |
1882 // If HeapDumpPath wasn't a file name then we append the default name | |
1883 if (use_default_filename) { | |
1884 char fn[32]; | |
1885 sprintf(fn, "java_pid%d.hprof", os::current_process_id()); | |
1886 assert(strlen(path) + strlen(fn) < sizeof(path), "HeapDumpPath too long"); | |
1887 strcat(path, fn); | |
1888 } | |
1889 | |
1890 HeapDumper dumper(false /* no GC before heap dump */, | |
1891 true /* send to tty */); | |
1892 dumper.dump(path); | |
1893 } |