Bug Summary

File:jdk/src/hotspot/share/services/heapDumper.cpp
Warning:line 1390, column 5
Value stored to 'length_in_bytes' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name heapDumper.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mthread-model posix -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-10/lib/clang/10.0.0 -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/hotspot/variant-server/libjvm/objs/precompiled -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -D __STDC_CONSTANT_MACROS -D _GNU_SOURCE -D _REENTRANT -D LIBC=gnu -D LINUX -D VM_LITTLE_ENDIAN -D _LP64=1 -D ASSERT -D CHECK_UNHANDLED_OOPS -D TARGET_ARCH_x86 -D INCLUDE_SUFFIX_OS=_linux -D INCLUDE_SUFFIX_CPU=_x86 -D INCLUDE_SUFFIX_COMPILER=_gcc -D TARGET_COMPILER_gcc -D AMD64 -D HOTSPOT_LIB_ARCH="amd64" -D COMPILER1 -D COMPILER2 -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/hotspot/variant-server/gensrc/adfiles -I /home/daniel/Projects/java/jdk/src/hotspot/share -I /home/daniel/Projects/java/jdk/src/hotspot/os/linux -I /home/daniel/Projects/java/jdk/src/hotspot/os/posix -I /home/daniel/Projects/java/jdk/src/hotspot/cpu/x86 -I /home/daniel/Projects/java/jdk/src/hotspot/os_cpu/linux_x86 -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/hotspot/variant-server/gensrc -I /home/daniel/Projects/java/jdk/src/hotspot/share/precompiled -I /home/daniel/Projects/java/jdk/src/hotspot/share/include -I /home/daniel/Projects/java/jdk/src/hotspot/os/posix/include -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/modules_include/java.base -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/modules_include/java.base/linux -I /home/daniel/Projects/java/jdk/src/java.base/share/native/libjimage -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/hotspot/variant-server/gensrc/adfiles -I /home/daniel/Projects/java/jdk/src/hotspot/share -I /home/daniel/Projects/java/jdk/src/hotspot/os/linux -I /home/daniel/Projects/java/jdk/src/hotspot/os/posix -I /home/daniel/Projects/java/jdk/src/hotspot/cpu/x86 -I /home/daniel/Projects/java/jdk/src/hotspot/os_cpu/linux_x86 -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/hotspot/variant-server/gensrc -D _FORTIFY_SOURCE=2 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/x86_64-linux-gnu/c++/7.5.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/x86_64-linux-gnu/c++/7.5.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-10/lib/clang/10.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-format-zero-length -Wno-unused-parameter -Wno-unused -Wno-parentheses -Wno-comment -Wno-unknown-pragmas -Wno-address -Wno-delete-non-virtual-dtor -Wno-char-subscripts -Wno-array-bounds -Wno-int-in-bool-context -Wno-ignored-qualifiers -Wno-missing-field-initializers -Wno-implicit-fallthrough -Wno-empty-body -Wno-strict-overflow -Wno-sequence-point -Wno-maybe-uninitialized -Wno-misleading-indentation -Wno-cast-function-type -Wno-shift-negative-value -std=c++14 -fdeprecated-macro -fdebug-compilation-dir /home/daniel/Projects/java/jdk/make/hotspot -ferror-limit 19 -fmessage-length 0 -fvisibility hidden -stack-protector 1 -fno-rtti -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o /home/daniel/Projects/java/scan/2021-12-21-193737-8510-1 -x c++ /home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp
1/*
2 * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25#include "precompiled.hpp"
26#include "jvm.h"
27#include "classfile/classLoaderData.inline.hpp"
28#include "classfile/classLoaderDataGraph.hpp"
29#include "classfile/javaClasses.inline.hpp"
30#include "classfile/symbolTable.hpp"
31#include "classfile/vmClasses.hpp"
32#include "classfile/vmSymbols.hpp"
33#include "gc/shared/gcLocker.hpp"
34#include "gc/shared/gcVMOperations.hpp"
35#include "gc/shared/workerThread.hpp"
36#include "jfr/jfrEvents.hpp"
37#include "memory/allocation.inline.hpp"
38#include "memory/resourceArea.hpp"
39#include "memory/universe.hpp"
40#include "oops/klass.inline.hpp"
41#include "oops/objArrayKlass.hpp"
42#include "oops/objArrayOop.inline.hpp"
43#include "oops/oop.inline.hpp"
44#include "oops/typeArrayOop.inline.hpp"
45#include "runtime/frame.inline.hpp"
46#include "runtime/handles.inline.hpp"
47#include "runtime/javaCalls.hpp"
48#include "runtime/jniHandles.hpp"
49#include "runtime/os.hpp"
50#include "runtime/reflectionUtils.hpp"
51#include "runtime/thread.inline.hpp"
52#include "runtime/threadSMR.hpp"
53#include "runtime/vframe.hpp"
54#include "runtime/vmOperations.hpp"
55#include "runtime/vmThread.hpp"
56#include "services/heapDumper.hpp"
57#include "services/heapDumperCompression.hpp"
58#include "services/threadService.hpp"
59#include "utilities/macros.hpp"
60#include "utilities/ostream.hpp"
61
62/*
63 * HPROF binary format - description copied from:
64 * src/share/demo/jvmti/hprof/hprof_io.c
65 *
66 *
67 * header "JAVA PROFILE 1.0.2" (0-terminated)
68 *
69 * u4 size of identifiers. Identifiers are used to represent
70 * UTF8 strings, objects, stack traces, etc. They usually
71 * have the same size as host pointers.
72 * u4 high word
73 * u4 low word number of milliseconds since 0:00 GMT, 1/1/70
74 * [record]* a sequence of records.
75 *
76 *
77 * Record format:
78 *
79 * u1 a TAG denoting the type of the record
80 * u4 number of *microseconds* since the time stamp in the
81 * header. (wraps around in a little more than an hour)
82 * u4 number of bytes *remaining* in the record. Note that
83 * this number excludes the tag and the length field itself.
84 * [u1]* BODY of the record (a sequence of bytes)
85 *
86 *
87 * The following TAGs are supported:
88 *
89 * TAG BODY notes
90 *----------------------------------------------------------
91 * HPROF_UTF8 a UTF8-encoded name
92 *
93 * id name ID
94 * [u1]* UTF8 characters (no trailing zero)
95 *
96 * HPROF_LOAD_CLASS a newly loaded class
97 *
98 * u4 class serial number (> 0)
99 * id class object ID
100 * u4 stack trace serial number
101 * id class name ID
102 *
103 * HPROF_UNLOAD_CLASS an unloading class
104 *
105 * u4 class serial_number
106 *
107 * HPROF_FRAME a Java stack frame
108 *
109 * id stack frame ID
110 * id method name ID
111 * id method signature ID
112 * id source file name ID
113 * u4 class serial number
114 * i4 line number. >0: normal
115 * -1: unknown
116 * -2: compiled method
117 * -3: native method
118 *
119 * HPROF_TRACE a Java stack trace
120 *
121 * u4 stack trace serial number
122 * u4 thread serial number
123 * u4 number of frames
124 * [id]* stack frame IDs
125 *
126 *
127 * HPROF_ALLOC_SITES a set of heap allocation sites, obtained after GC
128 *
129 * u2 flags 0x0001: incremental vs. complete
130 * 0x0002: sorted by allocation vs. live
131 * 0x0004: whether to force a GC
132 * u4 cutoff ratio
133 * u4 total live bytes
134 * u4 total live instances
135 * u8 total bytes allocated
136 * u8 total instances allocated
137 * u4 number of sites that follow
138 * [u1 is_array: 0: normal object
139 * 2: object array
140 * 4: boolean array
141 * 5: char array
142 * 6: float array
143 * 7: double array
144 * 8: byte array
145 * 9: short array
146 * 10: int array
147 * 11: long array
148 * u4 class serial number (may be zero during startup)
149 * u4 stack trace serial number
150 * u4 number of bytes alive
151 * u4 number of instances alive
152 * u4 number of bytes allocated
153 * u4]* number of instance allocated
154 *
155 * HPROF_START_THREAD a newly started thread.
156 *
157 * u4 thread serial number (> 0)
158 * id thread object ID
159 * u4 stack trace serial number
160 * id thread name ID
161 * id thread group name ID
162 * id thread group parent name ID
163 *
164 * HPROF_END_THREAD a terminating thread.
165 *
166 * u4 thread serial number
167 *
168 * HPROF_HEAP_SUMMARY heap summary
169 *
170 * u4 total live bytes
171 * u4 total live instances
172 * u8 total bytes allocated
173 * u8 total instances allocated
174 *
175 * HPROF_HEAP_DUMP denote a heap dump
176 *
177 * [heap dump sub-records]*
178 *
179 * There are four kinds of heap dump sub-records:
180 *
181 * u1 sub-record type
182 *
183 * HPROF_GC_ROOT_UNKNOWN unknown root
184 *
185 * id object ID
186 *
187 * HPROF_GC_ROOT_THREAD_OBJ thread object
188 *
189 * id thread object ID (may be 0 for a
190 * thread newly attached through JNI)
191 * u4 thread sequence number
192 * u4 stack trace sequence number
193 *
194 * HPROF_GC_ROOT_JNI_GLOBAL JNI global ref root
195 *
196 * id object ID
197 * id JNI global ref ID
198 *
199 * HPROF_GC_ROOT_JNI_LOCAL JNI local ref
200 *
201 * id object ID
202 * u4 thread serial number
203 * u4 frame # in stack trace (-1 for empty)
204 *
205 * HPROF_GC_ROOT_JAVA_FRAME Java stack frame
206 *
207 * id object ID
208 * u4 thread serial number
209 * u4 frame # in stack trace (-1 for empty)
210 *
211 * HPROF_GC_ROOT_NATIVE_STACK Native stack
212 *
213 * id object ID
214 * u4 thread serial number
215 *
216 * HPROF_GC_ROOT_STICKY_CLASS System class
217 *
218 * id object ID
219 *
220 * HPROF_GC_ROOT_THREAD_BLOCK Reference from thread block
221 *
222 * id object ID
223 * u4 thread serial number
224 *
225 * HPROF_GC_ROOT_MONITOR_USED Busy monitor
226 *
227 * id object ID
228 *
229 * HPROF_GC_CLASS_DUMP dump of a class object
230 *
231 * id class object ID
232 * u4 stack trace serial number
233 * id super class object ID
234 * id class loader object ID
235 * id signers object ID
236 * id protection domain object ID
237 * id reserved
238 * id reserved
239 *
240 * u4 instance size (in bytes)
241 *
242 * u2 size of constant pool
243 * [u2, constant pool index,
244 * ty, type
245 * 2: object
246 * 4: boolean
247 * 5: char
248 * 6: float
249 * 7: double
250 * 8: byte
251 * 9: short
252 * 10: int
253 * 11: long
254 * vl]* and value
255 *
256 * u2 number of static fields
257 * [id, static field name,
258 * ty, type,
259 * vl]* and value
260 *
261 * u2 number of inst. fields (not inc. super)
262 * [id, instance field name,
263 * ty]* type
264 *
265 * HPROF_GC_INSTANCE_DUMP dump of a normal object
266 *
267 * id object ID
268 * u4 stack trace serial number
269 * id class object ID
270 * u4 number of bytes that follow
271 * [vl]* instance field values (class, followed
272 * by super, super's super ...)
273 *
274 * HPROF_GC_OBJ_ARRAY_DUMP dump of an object array
275 *
276 * id array object ID
277 * u4 stack trace serial number
278 * u4 number of elements
279 * id array class ID
280 * [id]* elements
281 *
282 * HPROF_GC_PRIM_ARRAY_DUMP dump of a primitive array
283 *
284 * id array object ID
285 * u4 stack trace serial number
286 * u4 number of elements
287 * u1 element type
288 * 4: boolean array
289 * 5: char array
290 * 6: float array
291 * 7: double array
292 * 8: byte array
293 * 9: short array
294 * 10: int array
295 * 11: long array
296 * [u1]* elements
297 *
298 * HPROF_CPU_SAMPLES a set of sample traces of running threads
299 *
300 * u4 total number of samples
301 * u4 # of traces
302 * [u4 # of samples
303 * u4]* stack trace serial number
304 *
305 * HPROF_CONTROL_SETTINGS the settings of on/off switches
306 *
307 * u4 0x00000001: alloc traces on/off
308 * 0x00000002: cpu sampling on/off
309 * u2 stack trace depth
310 *
311 *
312 * When the header is "JAVA PROFILE 1.0.2" a heap dump can optionally
313 * be generated as a sequence of heap dump segments. This sequence is
314 * terminated by an end record. The additional tags allowed by format
315 * "JAVA PROFILE 1.0.2" are:
316 *
317 * HPROF_HEAP_DUMP_SEGMENT denote a heap dump segment
318 *
319 * [heap dump sub-records]*
320 * The same sub-record types allowed by HPROF_HEAP_DUMP
321 *
322 * HPROF_HEAP_DUMP_END denotes the end of a heap dump
323 *
324 */
325
326
327// HPROF tags
328
329enum hprofTag : u1 {
330 // top-level records
331 HPROF_UTF8 = 0x01,
332 HPROF_LOAD_CLASS = 0x02,
333 HPROF_UNLOAD_CLASS = 0x03,
334 HPROF_FRAME = 0x04,
335 HPROF_TRACE = 0x05,
336 HPROF_ALLOC_SITES = 0x06,
337 HPROF_HEAP_SUMMARY = 0x07,
338 HPROF_START_THREAD = 0x0A,
339 HPROF_END_THREAD = 0x0B,
340 HPROF_HEAP_DUMP = 0x0C,
341 HPROF_CPU_SAMPLES = 0x0D,
342 HPROF_CONTROL_SETTINGS = 0x0E,
343
344 // 1.0.2 record types
345 HPROF_HEAP_DUMP_SEGMENT = 0x1C,
346 HPROF_HEAP_DUMP_END = 0x2C,
347
348 // field types
349 HPROF_ARRAY_OBJECT = 0x01,
350 HPROF_NORMAL_OBJECT = 0x02,
351 HPROF_BOOLEAN = 0x04,
352 HPROF_CHAR = 0x05,
353 HPROF_FLOAT = 0x06,
354 HPROF_DOUBLE = 0x07,
355 HPROF_BYTE = 0x08,
356 HPROF_SHORT = 0x09,
357 HPROF_INT = 0x0A,
358 HPROF_LONG = 0x0B,
359
360 // data-dump sub-records
361 HPROF_GC_ROOT_UNKNOWN = 0xFF,
362 HPROF_GC_ROOT_JNI_GLOBAL = 0x01,
363 HPROF_GC_ROOT_JNI_LOCAL = 0x02,
364 HPROF_GC_ROOT_JAVA_FRAME = 0x03,
365 HPROF_GC_ROOT_NATIVE_STACK = 0x04,
366 HPROF_GC_ROOT_STICKY_CLASS = 0x05,
367 HPROF_GC_ROOT_THREAD_BLOCK = 0x06,
368 HPROF_GC_ROOT_MONITOR_USED = 0x07,
369 HPROF_GC_ROOT_THREAD_OBJ = 0x08,
370 HPROF_GC_CLASS_DUMP = 0x20,
371 HPROF_GC_INSTANCE_DUMP = 0x21,
372 HPROF_GC_OBJ_ARRAY_DUMP = 0x22,
373 HPROF_GC_PRIM_ARRAY_DUMP = 0x23
374};
375
376// Default stack trace ID (used for dummy HPROF_TRACE record)
377enum {
378 STACK_TRACE_ID = 1,
379 INITIAL_CLASS_COUNT = 200
380};
381
382// Supports I/O operations for a dump
383// Base class for dump and parallel dump
384class AbstractDumpWriter : public StackObj {
385 protected:
386 enum {
387 io_buffer_max_size = 1*M,
388 io_buffer_max_waste = 10*K,
389 dump_segment_header_size = 9
390 };
391
392 char* _buffer; // internal buffer
393 size_t _size;
394 size_t _pos;
395
396 bool _in_dump_segment; // Are we currently in a dump segment?
397 bool _is_huge_sub_record; // Are we writing a sub-record larger than the buffer size?
398 DEBUG_ONLY(size_t _sub_record_left;)size_t _sub_record_left; // The bytes not written for the current sub-record.
399 DEBUG_ONLY(bool _sub_record_ended;)bool _sub_record_ended; // True if we have called the end_sub_record().
400
401 virtual void flush(bool force = false) = 0;
402
403 char* buffer() const { return _buffer; }
404 size_t buffer_size() const { return _size; }
405 void set_position(size_t pos) { _pos = pos; }
406
407 // Can be called if we have enough room in the buffer.
408 void write_fast(const void* s, size_t len);
409
410 // Returns true if we have enough room in the buffer for 'len' bytes.
411 bool can_write_fast(size_t len);
412 public:
413 AbstractDumpWriter() :
414 _buffer(NULL__null),
415 _size(io_buffer_max_size),
416 _pos(0),
417 _in_dump_segment(false) { }
418
419 // total number of bytes written to the disk
420 virtual julong bytes_written() const = 0;
421 virtual char const* error() const = 0;
422
423 size_t position() const { return _pos; }
424 // writer functions
425 virtual void write_raw(const void* s, size_t len);
426 void write_u1(u1 x);
427 void write_u2(u2 x);
428 void write_u4(u4 x);
429 void write_u8(u8 x);
430 void write_objectID(oop o);
431 void write_symbolID(Symbol* o);
432 void write_classID(Klass* k);
433 void write_id(u4 x);
434
435 // Start a new sub-record. Starts a new heap dump segment if needed.
436 void start_sub_record(u1 tag, u4 len);
437 // Ends the current sub-record.
438 void end_sub_record();
439 // Finishes the current dump segment if not already finished.
440 void finish_dump_segment(bool force_flush = false);
441 // Refresh to get new buffer
442 void refresh() {
443 assert (_in_dump_segment ==false, "Sanity check")do { if (!(_in_dump_segment ==false)) { (*g_assert_poison) = 'X'
;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 443, "assert(" "_in_dump_segment ==false" ") failed", "Sanity check"
); ::breakpoint(); } } while (0)
;
444 _buffer = NULL__null;
445 _size = io_buffer_max_size;
446 _pos = 0;
447 // Force flush to guarantee data from parallel dumper are written.
448 flush(true);
449 }
450 // Called when finished to release the threads.
451 virtual void deactivate() = 0;
452};
453
454void AbstractDumpWriter::write_fast(const void* s, size_t len) {
455 assert(!_in_dump_segment || (_sub_record_left >= len), "sub-record too large")do { if (!(!_in_dump_segment || (_sub_record_left >= len))
) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 455, "assert(" "!_in_dump_segment || (_sub_record_left >= len)"
") failed", "sub-record too large"); ::breakpoint(); } } while
(0)
;
456 assert(buffer_size() - position() >= len, "Must fit")do { if (!(buffer_size() - position() >= len)) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 456, "assert(" "buffer_size() - position() >= len" ") failed"
, "Must fit"); ::breakpoint(); } } while (0)
;
457 debug_only(_sub_record_left -= len)_sub_record_left -= len;
458 memcpy(buffer() + position(), s, len);
459 set_position(position() + len);
460}
461
462bool AbstractDumpWriter::can_write_fast(size_t len) {
463 return buffer_size() - position() >= len;
464}
465
466// write raw bytes
467void AbstractDumpWriter::write_raw(const void* s, size_t len) {
468 assert(!_in_dump_segment || (_sub_record_left >= len), "sub-record too large")do { if (!(!_in_dump_segment || (_sub_record_left >= len))
) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 468, "assert(" "!_in_dump_segment || (_sub_record_left >= len)"
") failed", "sub-record too large"); ::breakpoint(); } } while
(0)
;
469 debug_only(_sub_record_left -= len)_sub_record_left -= len;
470
471 // flush buffer to make room.
472 while (len > buffer_size() - position()) {
473 assert(!_in_dump_segment || _is_huge_sub_record,do { if (!(!_in_dump_segment || _is_huge_sub_record)) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 474, "assert(" "!_in_dump_segment || _is_huge_sub_record" ") failed"
, "Cannot overflow in non-huge sub-record."); ::breakpoint();
} } while (0)
474 "Cannot overflow in non-huge sub-record.")do { if (!(!_in_dump_segment || _is_huge_sub_record)) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 474, "assert(" "!_in_dump_segment || _is_huge_sub_record" ") failed"
, "Cannot overflow in non-huge sub-record."); ::breakpoint();
} } while (0)
;
475 size_t to_write = buffer_size() - position();
476 memcpy(buffer() + position(), s, to_write);
477 s = (void*) ((char*) s + to_write);
478 len -= to_write;
479 set_position(position() + to_write);
480 flush();
481 }
482
483 memcpy(buffer() + position(), s, len);
484 set_position(position() + len);
485}
486
487// Makes sure we inline the fast write into the write_u* functions. This is a big speedup.
488#define WRITE_KNOWN_TYPE(p, len)do { if (can_write_fast((len))) write_fast((p), (len)); else write_raw
((p), (len)); } while (0)
do { if (can_write_fast((len))) write_fast((p), (len)); \
489 else write_raw((p), (len)); } while (0)
490
491void AbstractDumpWriter::write_u1(u1 x) {
492 WRITE_KNOWN_TYPE(&x, 1)do { if (can_write_fast((1))) write_fast((&x), (1)); else
write_raw((&x), (1)); } while (0)
;
493}
494
495void AbstractDumpWriter::write_u2(u2 x) {
496 u2 v;
497 Bytes::put_Java_u2((address)&v, x);
498 WRITE_KNOWN_TYPE(&v, 2)do { if (can_write_fast((2))) write_fast((&v), (2)); else
write_raw((&v), (2)); } while (0)
;
499}
500
501void AbstractDumpWriter::write_u4(u4 x) {
502 u4 v;
503 Bytes::put_Java_u4((address)&v, x);
504 WRITE_KNOWN_TYPE(&v, 4)do { if (can_write_fast((4))) write_fast((&v), (4)); else
write_raw((&v), (4)); } while (0)
;
505}
506
507void AbstractDumpWriter::write_u8(u8 x) {
508 u8 v;
509 Bytes::put_Java_u8((address)&v, x);
510 WRITE_KNOWN_TYPE(&v, 8)do { if (can_write_fast((8))) write_fast((&v), (8)); else
write_raw((&v), (8)); } while (0)
;
511}
512
513void AbstractDumpWriter::write_objectID(oop o) {
514 address a = cast_from_oop<address>(o);
515#ifdef _LP641
516 write_u8((u8)a);
517#else
518 write_u4((u4)a);
519#endif
520}
521
522void AbstractDumpWriter::write_symbolID(Symbol* s) {
523 address a = (address)((uintptr_t)s);
524#ifdef _LP641
525 write_u8((u8)a);
526#else
527 write_u4((u4)a);
528#endif
529}
530
531void AbstractDumpWriter::write_id(u4 x) {
532#ifdef _LP641
533 write_u8((u8) x);
534#else
535 write_u4(x);
536#endif
537}
538
539// We use java mirror as the class ID
540void AbstractDumpWriter::write_classID(Klass* k) {
541 write_objectID(k->java_mirror());
542}
543
544void AbstractDumpWriter::finish_dump_segment(bool force_flush) {
545 if (_in_dump_segment) {
546 assert(_sub_record_left == 0, "Last sub-record not written completely")do { if (!(_sub_record_left == 0)) { (*g_assert_poison) = 'X'
;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 546, "assert(" "_sub_record_left == 0" ") failed", "Last sub-record not written completely"
); ::breakpoint(); } } while (0)
;
547 assert(_sub_record_ended, "sub-record must have ended")do { if (!(_sub_record_ended)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 547, "assert(" "_sub_record_ended" ") failed", "sub-record must have ended"
); ::breakpoint(); } } while (0)
;
548
549 // Fix up the dump segment length if we haven't written a huge sub-record last
550 // (in which case the segment length was already set to the correct value initially).
551 if (!_is_huge_sub_record) {
552 assert(position() > dump_segment_header_size, "Dump segment should have some content")do { if (!(position() > dump_segment_header_size)) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 552, "assert(" "position() > dump_segment_header_size" ") failed"
, "Dump segment should have some content"); ::breakpoint(); }
} while (0)
;
553 Bytes::put_Java_u4((address) (buffer() + 5),
554 (u4) (position() - dump_segment_header_size));
555 } else {
556 // Finish process huge sub record
557 // Set _is_huge_sub_record to false so the parallel dump writer can flush data to file.
558 _is_huge_sub_record = false;
559 }
560
561 _in_dump_segment = false;
562 flush(force_flush);
563 }
564}
565
566void AbstractDumpWriter::start_sub_record(u1 tag, u4 len) {
567 if (!_in_dump_segment) {
568 if (position() > 0) {
569 flush();
570 }
571
572 assert(position() == 0 && buffer_size() > dump_segment_header_size, "Must be at the start")do { if (!(position() == 0 && buffer_size() > dump_segment_header_size
)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 572, "assert(" "position() == 0 && buffer_size() > dump_segment_header_size"
") failed", "Must be at the start"); ::breakpoint(); } } while
(0)
;
573
574 write_u1(HPROF_HEAP_DUMP_SEGMENT);
575 write_u4(0); // timestamp
576 // Will be fixed up later if we add more sub-records. If this is a huge sub-record,
577 // this is already the correct length, since we don't add more sub-records.
578 write_u4(len);
579 assert(Bytes::get_Java_u4((address)(buffer() + 5)) == len, "Inconsitent size!")do { if (!(Bytes::get_Java_u4((address)(buffer() + 5)) == len
)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 579, "assert(" "Bytes::get_Java_u4((address)(buffer() + 5)) == len"
") failed", "Inconsitent size!"); ::breakpoint(); } } while (
0)
;
580 _in_dump_segment = true;
581 _is_huge_sub_record = len > buffer_size() - dump_segment_header_size;
582 } else if (_is_huge_sub_record || (len > buffer_size() - position())) {
583 // This object will not fit in completely or the last sub-record was huge.
584 // Finish the current segement and try again.
585 finish_dump_segment();
586 start_sub_record(tag, len);
587
588 return;
589 }
590
591 debug_only(_sub_record_left = len)_sub_record_left = len;
592 debug_only(_sub_record_ended = false)_sub_record_ended = false;
593
594 write_u1(tag);
595}
596
597void AbstractDumpWriter::end_sub_record() {
598 assert(_in_dump_segment, "must be in dump segment")do { if (!(_in_dump_segment)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 598, "assert(" "_in_dump_segment" ") failed", "must be in dump segment"
); ::breakpoint(); } } while (0)
;
599 assert(_sub_record_left == 0, "sub-record not written completely")do { if (!(_sub_record_left == 0)) { (*g_assert_poison) = 'X'
;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 599, "assert(" "_sub_record_left == 0" ") failed", "sub-record not written completely"
); ::breakpoint(); } } while (0)
;
600 assert(!_sub_record_ended, "Must not have ended yet")do { if (!(!_sub_record_ended)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 600, "assert(" "!_sub_record_ended" ") failed", "Must not have ended yet"
); ::breakpoint(); } } while (0)
;
601 debug_only(_sub_record_ended = true)_sub_record_ended = true;
602}
603
604// Supports I/O operations for a dump
605
606class DumpWriter : public AbstractDumpWriter {
607 private:
608 CompressionBackend _backend; // Does the actual writing.
609 protected:
610 void flush(bool force = false) override;
611
612 public:
613 // Takes ownership of the writer and compressor.
614 DumpWriter(AbstractWriter* writer, AbstractCompressor* compressor);
615
616 // total number of bytes written to the disk
617 julong bytes_written() const override { return (julong) _backend.get_written(); }
618
619 char const* error() const override { return _backend.error(); }
620
621 // Called by threads used for parallel writing.
622 void writer_loop() { _backend.thread_loop(); }
623 // Called when finish to release the threads.
624 void deactivate() override { flush(); _backend.deactivate(); }
625 // Get the backend pointer, used by parallel dump writer.
626 CompressionBackend* backend_ptr() { return &_backend; }
627
628};
629
630// Check for error after constructing the object and destroy it in case of an error.
631DumpWriter::DumpWriter(AbstractWriter* writer, AbstractCompressor* compressor) :
632 AbstractDumpWriter(),
633 _backend(writer, compressor, io_buffer_max_size, io_buffer_max_waste) {
634 flush();
635}
636
637// flush any buffered bytes to the file
638void DumpWriter::flush(bool force) {
639 _backend.get_new_buffer(&_buffer, &_pos, &_size, force);
640}
641
642// Buffer queue used for parallel dump.
643struct ParWriterBufferQueueElem {
644 char* _buffer;
645 size_t _used;
646 ParWriterBufferQueueElem* _next;
647};
648
649class ParWriterBufferQueue : public CHeapObj<mtInternal> {
650 private:
651 ParWriterBufferQueueElem* _head;
652 ParWriterBufferQueueElem* _tail;
653 uint _length;
654 public:
655 ParWriterBufferQueue() : _head(NULL__null), _tail(NULL__null), _length(0) { }
656
657 void enqueue(ParWriterBufferQueueElem* entry) {
658 if (_head == NULL__null) {
659 assert(is_empty() && _tail == NULL, "Sanity check")do { if (!(is_empty() && _tail == __null)) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 659, "assert(" "is_empty() && _tail == __null" ") failed"
, "Sanity check"); ::breakpoint(); } } while (0)
;
660 _head = _tail = entry;
661 } else {
662 assert ((_tail->_next == NULL && _tail->_buffer != NULL), "Buffer queue is polluted")do { if (!((_tail->_next == __null && _tail->_buffer
!= __null))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 662, "assert(" "(_tail->_next == __null && _tail->_buffer != __null)"
") failed", "Buffer queue is polluted"); ::breakpoint(); } }
while (0)
;
663 _tail->_next = entry;
664 _tail = entry;
665 }
666 _length++;
667 assert(_tail->_next == NULL, "Bufer queue is polluted")do { if (!(_tail->_next == __null)) { (*g_assert_poison) =
'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 667, "assert(" "_tail->_next == __null" ") failed", "Bufer queue is polluted"
); ::breakpoint(); } } while (0)
;
668 }
669
670 ParWriterBufferQueueElem* dequeue() {
671 if (_head == NULL__null) return NULL__null;
672 ParWriterBufferQueueElem* entry = _head;
673 assert (entry->_buffer != NULL, "polluted buffer in writer list")do { if (!(entry->_buffer != __null)) { (*g_assert_poison)
= 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 673, "assert(" "entry->_buffer != __null" ") failed", "polluted buffer in writer list"
); ::breakpoint(); } } while (0)
;
674 _head = entry->_next;
675 if (_head == NULL__null) {
676 _tail = NULL__null;
677 }
678 entry->_next = NULL__null;
679 _length--;
680 return entry;
681 }
682
683 bool is_empty() {
684 return _length == 0;
685 }
686
687 uint length() { return _length; }
688};
689
690// Support parallel heap dump.
691class ParDumpWriter : public AbstractDumpWriter {
692 private:
693 // Lock used to guarantee the integrity of multiple buffers writing.
694 static Monitor* _lock;
695 // Pointer of backend from global DumpWriter.
696 CompressionBackend* _backend_ptr;
697 char const * _err;
698 ParWriterBufferQueue* _buffer_queue;
699 size_t _internal_buffer_used;
700 char* _buffer_base;
701 bool _split_data;
702 static const uint BackendFlushThreshold = 2;
703 protected:
704 void flush(bool force = false) override {
705 assert(_pos != 0, "must not be zero")do { if (!(_pos != 0)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 705, "assert(" "_pos != 0" ") failed", "must not be zero");
::breakpoint(); } } while (0)
;
706 if (_pos != 0) {
707 refresh_buffer();
708 }
709
710 if (_split_data || _is_huge_sub_record) {
711 return;
712 }
713
714 if (should_flush_buf_list(force)) {
715 assert(!_in_dump_segment && !_split_data && !_is_huge_sub_record, "incomplete data send to backend!\n")do { if (!(!_in_dump_segment && !_split_data &&
!_is_huge_sub_record)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 715, "assert(" "!_in_dump_segment && !_split_data && !_is_huge_sub_record"
") failed", "incomplete data send to backend!\n"); ::breakpoint
(); } } while (0)
;
716 flush_to_backend(force);
717 }
718 }
719
720 public:
721 // Check for error after constructing the object and destroy it in case of an error.
722 ParDumpWriter(DumpWriter* dw) :
723 AbstractDumpWriter(),
724 _backend_ptr(dw->backend_ptr()),
725 _buffer_queue((new (std::nothrow) ParWriterBufferQueue())),
726 _buffer_base(NULL__null),
727 _split_data(false) {
728 // prepare internal buffer
729 allocate_internal_buffer();
730 }
731
732 ~ParDumpWriter() {
733 assert(_buffer_queue != NULL, "Sanity check")do { if (!(_buffer_queue != __null)) { (*g_assert_poison) = 'X'
;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 733, "assert(" "_buffer_queue != __null" ") failed", "Sanity check"
); ::breakpoint(); } } while (0)
;
734 assert((_internal_buffer_used == 0) && (_buffer_queue->is_empty()),do { if (!((_internal_buffer_used == 0) && (_buffer_queue
->is_empty()))) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 735, "assert(" "(_internal_buffer_used == 0) && (_buffer_queue->is_empty())"
") failed", "All data must be send to backend"); ::breakpoint
(); } } while (0)
735 "All data must be send to backend")do { if (!((_internal_buffer_used == 0) && (_buffer_queue
->is_empty()))) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 735, "assert(" "(_internal_buffer_used == 0) && (_buffer_queue->is_empty())"
") failed", "All data must be send to backend"); ::breakpoint
(); } } while (0)
;
736 if (_buffer_base != NULL__null) {
737 os::free(_buffer_base);
738 _buffer_base = NULL__null;
739 }
740 delete _buffer_queue;
741 _buffer_queue = NULL__null;
742 }
743
744 // total number of bytes written to the disk
745 julong bytes_written() const override { return (julong) _backend_ptr->get_written(); }
746 char const* error() const override { return _err == NULL__null ? _backend_ptr->error() : _err; }
747
748 static void before_work() {
749 assert(_lock == NULL, "ParDumpWriter lock must be initialized only once")do { if (!(_lock == __null)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 749, "assert(" "_lock == __null" ") failed", "ParDumpWriter lock must be initialized only once"
); ::breakpoint(); } } while (0)
;
750 _lock = new (std::nothrow) PaddedMonitor(Mutex::safepoint, "ParallelHProfWriter_lock");
751 }
752
753 static void after_work() {
754 assert(_lock != NULL, "ParDumpWriter lock is not initialized")do { if (!(_lock != __null)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 754, "assert(" "_lock != __null" ") failed", "ParDumpWriter lock is not initialized"
); ::breakpoint(); } } while (0)
;
755 delete _lock;
756 _lock = NULL__null;
757 }
758
759 // write raw bytes
760 void write_raw(const void* s, size_t len) override {
761 assert(!_in_dump_segment || (_sub_record_left >= len), "sub-record too large")do { if (!(!_in_dump_segment || (_sub_record_left >= len))
) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 761, "assert(" "!_in_dump_segment || (_sub_record_left >= len)"
") failed", "sub-record too large"); ::breakpoint(); } } while
(0)
;
762 debug_only(_sub_record_left -= len)_sub_record_left -= len;
763 assert(!_split_data, "Invalid split data")do { if (!(!_split_data)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 763, "assert(" "!_split_data" ") failed", "Invalid split data"
); ::breakpoint(); } } while (0)
;
764 _split_data = true;
765 // flush buffer to make room.
766 while (len > buffer_size() - position()) {
767 assert(!_in_dump_segment || _is_huge_sub_record,do { if (!(!_in_dump_segment || _is_huge_sub_record)) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 768, "assert(" "!_in_dump_segment || _is_huge_sub_record" ") failed"
, "Cannot overflow in non-huge sub-record."); ::breakpoint();
} } while (0)
768 "Cannot overflow in non-huge sub-record.")do { if (!(!_in_dump_segment || _is_huge_sub_record)) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 768, "assert(" "!_in_dump_segment || _is_huge_sub_record" ") failed"
, "Cannot overflow in non-huge sub-record."); ::breakpoint();
} } while (0)
;
769 size_t to_write = buffer_size() - position();
770 memcpy(buffer() + position(), s, to_write);
771 s = (void*) ((char*) s + to_write);
772 len -= to_write;
773 set_position(position() + to_write);
774 flush();
775 }
776 _split_data = false;
777 memcpy(buffer() + position(), s, len);
778 set_position(position() + len);
779 }
780
781 void deactivate() override { flush(true); _backend_ptr->deactivate(); }
782
783 private:
784 void allocate_internal_buffer() {
785 assert(_buffer_queue != NULL, "Internal buffer queue is not ready when allocate internal buffer")do { if (!(_buffer_queue != __null)) { (*g_assert_poison) = 'X'
;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 785, "assert(" "_buffer_queue != __null" ") failed", "Internal buffer queue is not ready when allocate internal buffer"
); ::breakpoint(); } } while (0)
;
786 assert(_buffer == NULL && _buffer_base == NULL, "current buffer must be NULL before allocate")do { if (!(_buffer == __null && _buffer_base == __null
)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 786, "assert(" "_buffer == __null && _buffer_base == __null"
") failed", "current buffer must be NULL before allocate"); ::
breakpoint(); } } while (0)
;
787 _buffer_base = _buffer = (char*)os::malloc(io_buffer_max_size, mtInternal);
788 if (_buffer == NULL__null) {
789 set_error("Could not allocate buffer for writer");
790 return;
791 }
792 _pos = 0;
793 _internal_buffer_used = 0;
794 _size = io_buffer_max_size;
795 }
796
797 void set_error(char const* new_error) {
798 if ((new_error != NULL__null) && (_err == NULL__null)) {
799 _err = new_error;
800 }
801 }
802
803 // Add buffer to internal list
804 void refresh_buffer() {
805 size_t expected_total = _internal_buffer_used + _pos;
806 if (expected_total < io_buffer_max_size - io_buffer_max_waste) {
807 // reuse current buffer.
808 _internal_buffer_used = expected_total;
809 assert(_size - _pos == io_buffer_max_size - expected_total, "illegal resize of buffer")do { if (!(_size - _pos == io_buffer_max_size - expected_total
)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 809, "assert(" "_size - _pos == io_buffer_max_size - expected_total"
") failed", "illegal resize of buffer"); ::breakpoint(); } }
while (0)
;
810 _size -= _pos;
811 _buffer += _pos;
812 _pos = 0;
813
814 return;
815 }
816 // It is not possible here that expected_total is larger than io_buffer_max_size because
817 // of limitation in write_xxx().
818 assert(expected_total <= io_buffer_max_size, "buffer overflow")do { if (!(expected_total <= io_buffer_max_size)) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 818, "assert(" "expected_total <= io_buffer_max_size" ") failed"
, "buffer overflow"); ::breakpoint(); } } while (0)
;
819 assert(_buffer - _buffer_base <= io_buffer_max_size, "internal buffer overflow")do { if (!(_buffer - _buffer_base <= io_buffer_max_size)) {
(*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 819, "assert(" "_buffer - _buffer_base <= io_buffer_max_size"
") failed", "internal buffer overflow"); ::breakpoint(); } }
while (0)
;
820 ParWriterBufferQueueElem* entry =
821 (ParWriterBufferQueueElem*)os::malloc(sizeof(ParWriterBufferQueueElem), mtInternal);
822 if (entry == NULL__null) {
823 set_error("Heap dumper can allocate memory");
824 return;
825 }
826 entry->_buffer = _buffer_base;
827 entry->_used = expected_total;
828 entry->_next = NULL__null;
829 // add to internal buffer queue
830 _buffer_queue->enqueue(entry);
831 _buffer_base =_buffer = NULL__null;
832 allocate_internal_buffer();
833 }
834
835 void reclaim_entry(ParWriterBufferQueueElem* entry) {
836 assert(entry != NULL && entry->_buffer != NULL, "Invalid entry to reclaim")do { if (!(entry != __null && entry->_buffer != __null
)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 836, "assert(" "entry != __null && entry->_buffer != __null"
") failed", "Invalid entry to reclaim"); ::breakpoint(); } }
while (0)
;
837 os::free(entry->_buffer);
838 entry->_buffer = NULL__null;
839 os::free(entry);
840 }
841
842 void flush_buffer(char* buffer, size_t used) {
843 assert(_lock->owner() == Thread::current(), "flush buffer must hold lock")do { if (!(_lock->owner() == Thread::current())) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 843, "assert(" "_lock->owner() == Thread::current()" ") failed"
, "flush buffer must hold lock"); ::breakpoint(); } } while (
0)
;
844 size_t max = io_buffer_max_size;
845 // get_new_buffer
846 _backend_ptr->flush_external_buffer(buffer, used, max);
847 }
848
849 bool should_flush_buf_list(bool force) {
850 return force || _buffer_queue->length() > BackendFlushThreshold;
851 }
852
853 void flush_to_backend(bool force) {
854 // Guarantee there is only one writer updating the backend buffers.
855 MonitorLocker ml(_lock, Mutex::_no_safepoint_check_flag);
856 while (!_buffer_queue->is_empty()) {
857 ParWriterBufferQueueElem* entry = _buffer_queue->dequeue();
858 flush_buffer(entry->_buffer, entry->_used);
859 // Delete buffer and entry.
860 reclaim_entry(entry);
861 entry = NULL__null;
862 }
863 assert(_pos == 0, "available buffer must be empty before flush")do { if (!(_pos == 0)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 863, "assert(" "_pos == 0" ") failed", "available buffer must be empty before flush"
); ::breakpoint(); } } while (0)
;
864 // Flush internal buffer.
865 if (_internal_buffer_used > 0) {
866 flush_buffer(_buffer_base, _internal_buffer_used);
867 os::free(_buffer_base);
868 _pos = 0;
869 _internal_buffer_used = 0;
870 _buffer_base = _buffer = NULL__null;
871 // Allocate internal buffer for future use.
872 allocate_internal_buffer();
873 }
874 }
875};
876
877Monitor* ParDumpWriter::_lock = NULL__null;
878
879// Support class with a collection of functions used when dumping the heap
880
881class DumperSupport : AllStatic {
882 public:
883
884 // write a header of the given type
885 static void write_header(AbstractDumpWriter* writer, hprofTag tag, u4 len);
886
887 // returns hprof tag for the given type signature
888 static hprofTag sig2tag(Symbol* sig);
889 // returns hprof tag for the given basic type
890 static hprofTag type2tag(BasicType type);
891 // Returns the size of the data to write.
892 static u4 sig2size(Symbol* sig);
893
894 // returns the size of the instance of the given class
895 static u4 instance_size(Klass* k);
896
897 // dump a jfloat
898 static void dump_float(AbstractDumpWriter* writer, jfloat f);
899 // dump a jdouble
900 static void dump_double(AbstractDumpWriter* writer, jdouble d);
901 // dumps the raw value of the given field
902 static void dump_field_value(AbstractDumpWriter* writer, char type, oop obj, int offset);
903 // returns the size of the static fields; also counts the static fields
904 static u4 get_static_fields_size(InstanceKlass* ik, u2& field_count);
905 // dumps static fields of the given class
906 static void dump_static_fields(AbstractDumpWriter* writer, Klass* k);
907 // dump the raw values of the instance fields of the given object
908 static void dump_instance_fields(AbstractDumpWriter* writer, oop o);
909 // get the count of the instance fields for a given class
910 static u2 get_instance_fields_count(InstanceKlass* ik);
911 // dumps the definition of the instance fields for a given class
912 static void dump_instance_field_descriptors(AbstractDumpWriter* writer, Klass* k);
913 // creates HPROF_GC_INSTANCE_DUMP record for the given object
914 static void dump_instance(AbstractDumpWriter* writer, oop o);
915 // creates HPROF_GC_CLASS_DUMP record for the given class and each of its
916 // array classes
917 static void dump_class_and_array_classes(AbstractDumpWriter* writer, Klass* k);
918 // creates HPROF_GC_CLASS_DUMP record for a given primitive array
919 // class (and each multi-dimensional array class too)
920 static void dump_basic_type_array_class(AbstractDumpWriter* writer, Klass* k);
921
922 // creates HPROF_GC_OBJ_ARRAY_DUMP record for the given object array
923 static void dump_object_array(AbstractDumpWriter* writer, objArrayOop array);
924 // creates HPROF_GC_PRIM_ARRAY_DUMP record for the given type array
925 static void dump_prim_array(AbstractDumpWriter* writer, typeArrayOop array);
926 // create HPROF_FRAME record for the given method and bci
927 static void dump_stack_frame(AbstractDumpWriter* writer, int frame_serial_num, int class_serial_num, Method* m, int bci);
928
929 // check if we need to truncate an array
930 static int calculate_array_max_length(AbstractDumpWriter* writer, arrayOop array, short header_size);
931
932 // fixes up the current dump record and writes HPROF_HEAP_DUMP_END record
933 static void end_of_dump(AbstractDumpWriter* writer);
934
935 static oop mask_dormant_archived_object(oop o) {
936 if (o != NULL__null && o->klass()->java_mirror() == NULL__null) {
937 // Ignore this object since the corresponding java mirror is not loaded.
938 // Might be a dormant archive object.
939 return NULL__null;
940 } else {
941 return o;
942 }
943 }
944};
945
946// write a header of the given type
947void DumperSupport:: write_header(AbstractDumpWriter* writer, hprofTag tag, u4 len) {
948 writer->write_u1(tag);
949 writer->write_u4(0); // current ticks
950 writer->write_u4(len);
951}
952
953// returns hprof tag for the given type signature
954hprofTag DumperSupport::sig2tag(Symbol* sig) {
955 switch (sig->char_at(0)) {
956 case JVM_SIGNATURE_CLASS : return HPROF_NORMAL_OBJECT;
957 case JVM_SIGNATURE_ARRAY : return HPROF_NORMAL_OBJECT;
958 case JVM_SIGNATURE_BYTE : return HPROF_BYTE;
959 case JVM_SIGNATURE_CHAR : return HPROF_CHAR;
960 case JVM_SIGNATURE_FLOAT : return HPROF_FLOAT;
961 case JVM_SIGNATURE_DOUBLE : return HPROF_DOUBLE;
962 case JVM_SIGNATURE_INT : return HPROF_INT;
963 case JVM_SIGNATURE_LONG : return HPROF_LONG;
964 case JVM_SIGNATURE_SHORT : return HPROF_SHORT;
965 case JVM_SIGNATURE_BOOLEAN : return HPROF_BOOLEAN;
966 default : ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here(
"/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 966); ::breakpoint(); } while (0)
; /* to shut up compiler */ return HPROF_BYTE;
967 }
968}
969
970hprofTag DumperSupport::type2tag(BasicType type) {
971 switch (type) {
972 case T_BYTE : return HPROF_BYTE;
973 case T_CHAR : return HPROF_CHAR;
974 case T_FLOAT : return HPROF_FLOAT;
975 case T_DOUBLE : return HPROF_DOUBLE;
976 case T_INT : return HPROF_INT;
977 case T_LONG : return HPROF_LONG;
978 case T_SHORT : return HPROF_SHORT;
979 case T_BOOLEAN : return HPROF_BOOLEAN;
980 default : ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here(
"/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 980); ::breakpoint(); } while (0)
; /* to shut up compiler */ return HPROF_BYTE;
981 }
982}
983
984u4 DumperSupport::sig2size(Symbol* sig) {
985 switch (sig->char_at(0)) {
986 case JVM_SIGNATURE_CLASS:
987 case JVM_SIGNATURE_ARRAY: return sizeof(address);
988 case JVM_SIGNATURE_BOOLEAN:
989 case JVM_SIGNATURE_BYTE: return 1;
990 case JVM_SIGNATURE_SHORT:
991 case JVM_SIGNATURE_CHAR: return 2;
992 case JVM_SIGNATURE_INT:
993 case JVM_SIGNATURE_FLOAT: return 4;
994 case JVM_SIGNATURE_LONG:
995 case JVM_SIGNATURE_DOUBLE: return 8;
996 default: ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here(
"/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 996); ::breakpoint(); } while (0)
; /* to shut up compiler */ return 0;
997 }
998}
999
1000template<typename T, typename F> T bit_cast(F from) { // replace with the real thing when we can use c++20
1001 T to;
1002 static_assert(sizeof(to) == sizeof(from), "must be of the same size");
1003 memcpy(&to, &from, sizeof(to));
1004 return to;
1005}
1006
1007// dump a jfloat
1008void DumperSupport::dump_float(AbstractDumpWriter* writer, jfloat f) {
1009 if (g_isnan(f)) {
1010 writer->write_u4(0x7fc00000); // collapsing NaNs
1011 } else {
1012 writer->write_u4(bit_cast<u4>(f));
1013 }
1014}
1015
1016// dump a jdouble
1017void DumperSupport::dump_double(AbstractDumpWriter* writer, jdouble d) {
1018 if (g_isnan(d)) {
1019 writer->write_u8(0x7ff80000ull << 32); // collapsing NaNs
1020 } else {
1021 writer->write_u8(bit_cast<u8>(d));
1022 }
1023}
1024
1025// dumps the raw value of the given field
1026void DumperSupport::dump_field_value(AbstractDumpWriter* writer, char type, oop obj, int offset) {
1027 switch (type) {
1028 case JVM_SIGNATURE_CLASS :
1029 case JVM_SIGNATURE_ARRAY : {
1030 oop o = obj->obj_field_access<ON_UNKNOWN_OOP_REF | AS_NO_KEEPALIVE>(offset);
1031 if (o != NULL__null && log_is_enabled(Debug, cds, heap)(LogImpl<(LogTag::_cds), (LogTag::_heap), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)
>::is_level(LogLevel::Debug))
&& mask_dormant_archived_object(o) == NULL__null) {
1032 ResourceMark rm;
1033 log_debug(cds, heap)(!(LogImpl<(LogTag::_cds), (LogTag::_heap), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)
>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag
::_cds), (LogTag::_heap), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel
::Debug>
("skipped dormant archived object " INTPTR_FORMAT"0x%016" "l" "x" " (%s) referenced by " INTPTR_FORMAT"0x%016" "l" "x" " (%s)",
1034 p2i(o), o->klass()->external_name(),
1035 p2i(obj), obj->klass()->external_name());
1036 }
1037 o = mask_dormant_archived_object(o);
1038 assert(oopDesc::is_oop_or_null(o), "Expected an oop or NULL at " PTR_FORMAT, p2i(o))do { if (!(oopDesc::is_oop_or_null(o))) { (*g_assert_poison) =
'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1038, "assert(" "oopDesc::is_oop_or_null(o)" ") failed", "Expected an oop or NULL at "
"0x%016" "l" "x", p2i(o)); ::breakpoint(); } } while (0)
;
1039 writer->write_objectID(o);
1040 break;
1041 }
1042 case JVM_SIGNATURE_BYTE : {
1043 jbyte b = obj->byte_field(offset);
1044 writer->write_u1(b);
1045 break;
1046 }
1047 case JVM_SIGNATURE_CHAR : {
1048 jchar c = obj->char_field(offset);
1049 writer->write_u2(c);
1050 break;
1051 }
1052 case JVM_SIGNATURE_SHORT : {
1053 jshort s = obj->short_field(offset);
1054 writer->write_u2(s);
1055 break;
1056 }
1057 case JVM_SIGNATURE_FLOAT : {
1058 jfloat f = obj->float_field(offset);
1059 dump_float(writer, f);
1060 break;
1061 }
1062 case JVM_SIGNATURE_DOUBLE : {
1063 jdouble d = obj->double_field(offset);
1064 dump_double(writer, d);
1065 break;
1066 }
1067 case JVM_SIGNATURE_INT : {
1068 jint i = obj->int_field(offset);
1069 writer->write_u4(i);
1070 break;
1071 }
1072 case JVM_SIGNATURE_LONG : {
1073 jlong l = obj->long_field(offset);
1074 writer->write_u8(l);
1075 break;
1076 }
1077 case JVM_SIGNATURE_BOOLEAN : {
1078 jboolean b = obj->bool_field(offset);
1079 writer->write_u1(b);
1080 break;
1081 }
1082 default : {
1083 ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here(
"/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1083); ::breakpoint(); } while (0)
;
1084 break;
1085 }
1086 }
1087}
1088
1089// returns the size of the instance of the given class
1090u4 DumperSupport::instance_size(Klass* k) {
1091 InstanceKlass* ik = InstanceKlass::cast(k);
1092 u4 size = 0;
1093
1094 for (FieldStream fld(ik, false, false); !fld.eos(); fld.next()) {
1095 if (!fld.access_flags().is_static()) {
1096 size += sig2size(fld.signature());
1097 }
1098 }
1099 return size;
1100}
1101
1102u4 DumperSupport::get_static_fields_size(InstanceKlass* ik, u2& field_count) {
1103 field_count = 0;
1104 u4 size = 0;
1105
1106 for (FieldStream fldc(ik, true, true); !fldc.eos(); fldc.next()) {
1107 if (fldc.access_flags().is_static()) {
1108 field_count++;
1109 size += sig2size(fldc.signature());
1110 }
1111 }
1112
1113 // Add in resolved_references which is referenced by the cpCache
1114 // The resolved_references is an array per InstanceKlass holding the
1115 // strings and other oops resolved from the constant pool.
1116 oop resolved_references = ik->constants()->resolved_references_or_null();
1117 if (resolved_references != NULL__null) {
1118 field_count++;
1119 size += sizeof(address);
1120
1121 // Add in the resolved_references of the used previous versions of the class
1122 // in the case of RedefineClasses
1123 InstanceKlass* prev = ik->previous_versions();
1124 while (prev != NULL__null && prev->constants()->resolved_references_or_null() != NULL__null) {
1125 field_count++;
1126 size += sizeof(address);
1127 prev = prev->previous_versions();
1128 }
1129 }
1130
1131 // Also provide a pointer to the init_lock if present, so there aren't unreferenced int[0]
1132 // arrays.
1133 oop init_lock = ik->init_lock();
1134 if (init_lock != NULL__null) {
1135 field_count++;
1136 size += sizeof(address);
1137 }
1138
1139 // We write the value itself plus a name and a one byte type tag per field.
1140 return size + field_count * (sizeof(address) + 1);
1141}
1142
1143// dumps static fields of the given class
1144void DumperSupport::dump_static_fields(AbstractDumpWriter* writer, Klass* k) {
1145 InstanceKlass* ik = InstanceKlass::cast(k);
1146
1147 // dump the field descriptors and raw values
1148 for (FieldStream fld(ik, true, true); !fld.eos(); fld.next()) {
1149 if (fld.access_flags().is_static()) {
1150 Symbol* sig = fld.signature();
1151
1152 writer->write_symbolID(fld.name()); // name
1153 writer->write_u1(sig2tag(sig)); // type
1154
1155 // value
1156 dump_field_value(writer, sig->char_at(0), ik->java_mirror(), fld.offset());
1157 }
1158 }
1159
1160 // Add resolved_references for each class that has them
1161 oop resolved_references = ik->constants()->resolved_references_or_null();
1162 if (resolved_references != NULL__null) {
1163 writer->write_symbolID(vmSymbols::resolved_references_name()); // name
1164 writer->write_u1(sig2tag(vmSymbols::object_array_signature())); // type
1165 writer->write_objectID(resolved_references);
1166
1167 // Also write any previous versions
1168 InstanceKlass* prev = ik->previous_versions();
1169 while (prev != NULL__null && prev->constants()->resolved_references_or_null() != NULL__null) {
1170 writer->write_symbolID(vmSymbols::resolved_references_name()); // name
1171 writer->write_u1(sig2tag(vmSymbols::object_array_signature())); // type
1172 writer->write_objectID(prev->constants()->resolved_references());
1173 prev = prev->previous_versions();
1174 }
1175 }
1176
1177 // Add init lock to the end if the class is not yet initialized
1178 oop init_lock = ik->init_lock();
1179 if (init_lock != NULL__null) {
1180 writer->write_symbolID(vmSymbols::init_lock_name()); // name
1181 writer->write_u1(sig2tag(vmSymbols::int_array_signature())); // type
1182 writer->write_objectID(init_lock);
1183 }
1184}
1185
1186// dump the raw values of the instance fields of the given object
1187void DumperSupport::dump_instance_fields(AbstractDumpWriter* writer, oop o) {
1188 InstanceKlass* ik = InstanceKlass::cast(o->klass());
1189
1190 for (FieldStream fld(ik, false, false); !fld.eos(); fld.next()) {
1191 if (!fld.access_flags().is_static()) {
1192 Symbol* sig = fld.signature();
1193 dump_field_value(writer, sig->char_at(0), o, fld.offset());
1194 }
1195 }
1196}
1197
1198// dumps the definition of the instance fields for a given class
1199u2 DumperSupport::get_instance_fields_count(InstanceKlass* ik) {
1200 u2 field_count = 0;
1201
1202 for (FieldStream fldc(ik, true, true); !fldc.eos(); fldc.next()) {
1203 if (!fldc.access_flags().is_static()) field_count++;
1204 }
1205
1206 return field_count;
1207}
1208
1209// dumps the definition of the instance fields for a given class
1210void DumperSupport::dump_instance_field_descriptors(AbstractDumpWriter* writer, Klass* k) {
1211 InstanceKlass* ik = InstanceKlass::cast(k);
1212
1213 // dump the field descriptors
1214 for (FieldStream fld(ik, true, true); !fld.eos(); fld.next()) {
1215 if (!fld.access_flags().is_static()) {
1216 Symbol* sig = fld.signature();
1217
1218 writer->write_symbolID(fld.name()); // name
1219 writer->write_u1(sig2tag(sig)); // type
1220 }
1221 }
1222}
1223
1224// creates HPROF_GC_INSTANCE_DUMP record for the given object
1225void DumperSupport::dump_instance(AbstractDumpWriter* writer, oop o) {
1226 InstanceKlass* ik = InstanceKlass::cast(o->klass());
1227 u4 is = instance_size(ik);
1228 u4 size = 1 + sizeof(address) + 4 + sizeof(address) + 4 + is;
1229
1230 writer->start_sub_record(HPROF_GC_INSTANCE_DUMP, size);
1231 writer->write_objectID(o);
1232 writer->write_u4(STACK_TRACE_ID);
1233
1234 // class ID
1235 writer->write_classID(ik);
1236
1237 // number of bytes that follow
1238 writer->write_u4(is);
1239
1240 // field values
1241 dump_instance_fields(writer, o);
1242
1243 writer->end_sub_record();
1244}
1245
1246// creates HPROF_GC_CLASS_DUMP record for the given class and each of
1247// its array classes
1248void DumperSupport::dump_class_and_array_classes(AbstractDumpWriter* writer, Klass* k) {
1249 InstanceKlass* ik = InstanceKlass::cast(k);
1250
1251 // We can safepoint and do a heap dump at a point where we have a Klass,
1252 // but no java mirror class has been setup for it. So we need to check
1253 // that the class is at least loaded, to avoid crash from a null mirror.
1254 if (!ik->is_loaded()) {
1255 return;
1256 }
1257
1258 u2 static_fields_count = 0;
1259 u4 static_size = get_static_fields_size(ik, static_fields_count);
1260 u2 instance_fields_count = get_instance_fields_count(ik);
1261 u4 instance_fields_size = instance_fields_count * (sizeof(address) + 1);
1262 u4 size = 1 + sizeof(address) + 4 + 6 * sizeof(address) + 4 + 2 + 2 + static_size + 2 + instance_fields_size;
1263
1264 writer->start_sub_record(HPROF_GC_CLASS_DUMP, size);
1265
1266 // class ID
1267 writer->write_classID(ik);
1268 writer->write_u4(STACK_TRACE_ID);
1269
1270 // super class ID
1271 InstanceKlass* java_super = ik->java_super();
1272 if (java_super == NULL__null) {
1273 writer->write_objectID(oop(NULL__null));
1274 } else {
1275 writer->write_classID(java_super);
1276 }
1277
1278 writer->write_objectID(ik->class_loader());
1279 writer->write_objectID(ik->signers());
1280 writer->write_objectID(ik->protection_domain());
1281
1282 // reserved
1283 writer->write_objectID(oop(NULL__null));
1284 writer->write_objectID(oop(NULL__null));
1285
1286 // instance size
1287 writer->write_u4(DumperSupport::instance_size(ik));
1288
1289 // size of constant pool - ignored by HAT 1.1
1290 writer->write_u2(0);
1291
1292 // static fields
1293 writer->write_u2(static_fields_count);
1294 dump_static_fields(writer, ik);
1295
1296 // description of instance fields
1297 writer->write_u2(instance_fields_count);
1298 dump_instance_field_descriptors(writer, ik);
1299
1300 writer->end_sub_record();
1301
1302 // array classes
1303 k = ik->array_klass_or_null();
1304 while (k != NULL__null) {
1305 assert(k->is_objArray_klass(), "not an ObjArrayKlass")do { if (!(k->is_objArray_klass())) { (*g_assert_poison) =
'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1305, "assert(" "k->is_objArray_klass()" ") failed", "not an ObjArrayKlass"
); ::breakpoint(); } } while (0)
;
1306
1307 u4 size = 1 + sizeof(address) + 4 + 6 * sizeof(address) + 4 + 2 + 2 + 2;
1308 writer->start_sub_record(HPROF_GC_CLASS_DUMP, size);
1309 writer->write_classID(k);
1310 writer->write_u4(STACK_TRACE_ID);
1311
1312 // super class of array classes is java.lang.Object
1313 java_super = k->java_super();
1314 assert(java_super != NULL, "checking")do { if (!(java_super != __null)) { (*g_assert_poison) = 'X';
; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1314, "assert(" "java_super != __null" ") failed", "checking"
); ::breakpoint(); } } while (0)
;
1315 writer->write_classID(java_super);
1316
1317 writer->write_objectID(ik->class_loader());
1318 writer->write_objectID(ik->signers());
1319 writer->write_objectID(ik->protection_domain());
1320
1321 writer->write_objectID(oop(NULL__null)); // reserved
1322 writer->write_objectID(oop(NULL__null));
1323 writer->write_u4(0); // instance size
1324 writer->write_u2(0); // constant pool
1325 writer->write_u2(0); // static fields
1326 writer->write_u2(0); // instance fields
1327
1328 writer->end_sub_record();
1329
1330 // get the array class for the next rank
1331 k = k->array_klass_or_null();
1332 }
1333}
1334
1335// creates HPROF_GC_CLASS_DUMP record for a given primitive array
1336// class (and each multi-dimensional array class too)
1337void DumperSupport::dump_basic_type_array_class(AbstractDumpWriter* writer, Klass* k) {
1338 // array classes
1339 while (k != NULL__null) {
1340 Klass* klass = k;
1341
1342 u4 size = 1 + sizeof(address) + 4 + 6 * sizeof(address) + 4 + 2 + 2 + 2;
1343 writer->start_sub_record(HPROF_GC_CLASS_DUMP, size);
1344 writer->write_classID(klass);
1345 writer->write_u4(STACK_TRACE_ID);
1346
1347 // super class of array classes is java.lang.Object
1348 InstanceKlass* java_super = klass->java_super();
1349 assert(java_super != NULL, "checking")do { if (!(java_super != __null)) { (*g_assert_poison) = 'X';
; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1349, "assert(" "java_super != __null" ") failed", "checking"
); ::breakpoint(); } } while (0)
;
1350 writer->write_classID(java_super);
1351
1352 writer->write_objectID(oop(NULL__null)); // loader
1353 writer->write_objectID(oop(NULL__null)); // signers
1354 writer->write_objectID(oop(NULL__null)); // protection domain
1355
1356 writer->write_objectID(oop(NULL__null)); // reserved
1357 writer->write_objectID(oop(NULL__null));
1358 writer->write_u4(0); // instance size
1359 writer->write_u2(0); // constant pool
1360 writer->write_u2(0); // static fields
1361 writer->write_u2(0); // instance fields
1362
1363 writer->end_sub_record();
1364
1365 // get the array class for the next rank
1366 k = klass->array_klass_or_null();
1367 }
1368}
1369
1370// Hprof uses an u4 as record length field,
1371// which means we need to truncate arrays that are too long.
1372int DumperSupport::calculate_array_max_length(AbstractDumpWriter* writer, arrayOop array, short header_size) {
1373 BasicType type = ArrayKlass::cast(array->klass())->element_type();
1374 assert(type >= T_BOOLEAN && type <= T_OBJECT, "invalid array element type")do { if (!(type >= T_BOOLEAN && type <= T_OBJECT
)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1374, "assert(" "type >= T_BOOLEAN && type <= T_OBJECT"
") failed", "invalid array element type"); ::breakpoint(); }
} while (0)
;
1375
1376 int length = array->length();
1377
1378 int type_size;
1379 if (type == T_OBJECT) {
1380 type_size = sizeof(address);
1381 } else {
1382 type_size = type2aelembytes(type);
1383 }
1384
1385 size_t length_in_bytes = (size_t)length * type_size;
1386 uint max_bytes = max_juint - header_size;
1387
1388 if (length_in_bytes > max_bytes) {
1389 length = max_bytes / type_size;
1390 length_in_bytes = (size_t)length * type_size;
Value stored to 'length_in_bytes' is never read
1391
1392 warning("cannot dump array of type %s[] with length %d; truncating to length %d",
1393 type2name_tab[type], array->length(), length);
1394 }
1395 return length;
1396}
1397
1398// creates HPROF_GC_OBJ_ARRAY_DUMP record for the given object array
1399void DumperSupport::dump_object_array(AbstractDumpWriter* writer, objArrayOop array) {
1400 // sizeof(u1) + 2 * sizeof(u4) + sizeof(objectID) + sizeof(classID)
1401 short header_size = 1 + 2 * 4 + 2 * sizeof(address);
1402 int length = calculate_array_max_length(writer, array, header_size);
1403 u4 size = header_size + length * sizeof(address);
1404
1405 writer->start_sub_record(HPROF_GC_OBJ_ARRAY_DUMP, size);
1406 writer->write_objectID(array);
1407 writer->write_u4(STACK_TRACE_ID);
1408 writer->write_u4(length);
1409
1410 // array class ID
1411 writer->write_classID(array->klass());
1412
1413 // [id]* elements
1414 for (int index = 0; index < length; index++) {
1415 oop o = array->obj_at(index);
1416 if (o != NULL__null && log_is_enabled(Debug, cds, heap)(LogImpl<(LogTag::_cds), (LogTag::_heap), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)
>::is_level(LogLevel::Debug))
&& mask_dormant_archived_object(o) == NULL__null) {
1417 ResourceMark rm;
1418 log_debug(cds, heap)(!(LogImpl<(LogTag::_cds), (LogTag::_heap), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)
>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag
::_cds), (LogTag::_heap), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel
::Debug>
("skipped dormant archived object " INTPTR_FORMAT"0x%016" "l" "x" " (%s) referenced by " INTPTR_FORMAT"0x%016" "l" "x" " (%s)",
1419 p2i(o), o->klass()->external_name(),
1420 p2i(array), array->klass()->external_name());
1421 }
1422 o = mask_dormant_archived_object(o);
1423 writer->write_objectID(o);
1424 }
1425
1426 writer->end_sub_record();
1427}
1428
1429#define WRITE_ARRAY(Array, Type, Size, Length)for (int i = 0; i < Length; i++) { writer->write_Size((
Size)Array->Type_at(i)); }
\
1430 for (int i = 0; i < Length; i++) { writer->write_##Size((Size)Array->Type##_at(i)); }
1431
1432// creates HPROF_GC_PRIM_ARRAY_DUMP record for the given type array
1433void DumperSupport::dump_prim_array(AbstractDumpWriter* writer, typeArrayOop array) {
1434 BasicType type = TypeArrayKlass::cast(array->klass())->element_type();
1435 // 2 * sizeof(u1) + 2 * sizeof(u4) + sizeof(objectID)
1436 short header_size = 2 * 1 + 2 * 4 + sizeof(address);
1437
1438 int length = calculate_array_max_length(writer, array, header_size);
1439 int type_size = type2aelembytes(type);
1440 u4 length_in_bytes = (u4)length * type_size;
1441 u4 size = header_size + length_in_bytes;
1442
1443 writer->start_sub_record(HPROF_GC_PRIM_ARRAY_DUMP, size);
1444 writer->write_objectID(array);
1445 writer->write_u4(STACK_TRACE_ID);
1446 writer->write_u4(length);
1447 writer->write_u1(type2tag(type));
1448
1449 // nothing to copy
1450 if (length == 0) {
1451 writer->end_sub_record();
1452 return;
1453 }
1454
1455 // If the byte ordering is big endian then we can copy most types directly
1456
1457 switch (type) {
1458 case T_INT : {
1459 if (Endian::is_Java_byte_ordering_different()) {
1460 WRITE_ARRAY(array, int, u4, length)for (int i = 0; i < length; i++) { writer->write_u4((u4
)array->int_at(i)); }
;
1461 } else {
1462 writer->write_raw(array->int_at_addr(0), length_in_bytes);
1463 }
1464 break;
1465 }
1466 case T_BYTE : {
1467 writer->write_raw(array->byte_at_addr(0), length_in_bytes);
1468 break;
1469 }
1470 case T_CHAR : {
1471 if (Endian::is_Java_byte_ordering_different()) {
1472 WRITE_ARRAY(array, char, u2, length)for (int i = 0; i < length; i++) { writer->write_u2((u2
)array->char_at(i)); }
;
1473 } else {
1474 writer->write_raw(array->char_at_addr(0), length_in_bytes);
1475 }
1476 break;
1477 }
1478 case T_SHORT : {
1479 if (Endian::is_Java_byte_ordering_different()) {
1480 WRITE_ARRAY(array, short, u2, length)for (int i = 0; i < length; i++) { writer->write_u2((u2
)array->short_at(i)); }
;
1481 } else {
1482 writer->write_raw(array->short_at_addr(0), length_in_bytes);
1483 }
1484 break;
1485 }
1486 case T_BOOLEAN : {
1487 if (Endian::is_Java_byte_ordering_different()) {
1488 WRITE_ARRAY(array, bool, u1, length)for (int i = 0; i < length; i++) { writer->write_u1((u1
)array->bool_at(i)); }
;
1489 } else {
1490 writer->write_raw(array->bool_at_addr(0), length_in_bytes);
1491 }
1492 break;
1493 }
1494 case T_LONG : {
1495 if (Endian::is_Java_byte_ordering_different()) {
1496 WRITE_ARRAY(array, long, u8, length)for (int i = 0; i < length; i++) { writer->write_u8((u8
)array->long_at(i)); }
;
1497 } else {
1498 writer->write_raw(array->long_at_addr(0), length_in_bytes);
1499 }
1500 break;
1501 }
1502
1503 // handle float/doubles in a special value to ensure than NaNs are
1504 // written correctly. TO DO: Check if we can avoid this on processors that
1505 // use IEEE 754.
1506
1507 case T_FLOAT : {
1508 for (int i = 0; i < length; i++) {
1509 dump_float(writer, array->float_at(i));
1510 }
1511 break;
1512 }
1513 case T_DOUBLE : {
1514 for (int i = 0; i < length; i++) {
1515 dump_double(writer, array->double_at(i));
1516 }
1517 break;
1518 }
1519 default : ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here(
"/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1519); ::breakpoint(); } while (0)
;
1520 }
1521
1522 writer->end_sub_record();
1523}
1524
1525// create a HPROF_FRAME record of the given Method* and bci
1526void DumperSupport::dump_stack_frame(AbstractDumpWriter* writer,
1527 int frame_serial_num,
1528 int class_serial_num,
1529 Method* m,
1530 int bci) {
1531 int line_number;
1532 if (m->is_native()) {
1533 line_number = -3; // native frame
1534 } else {
1535 line_number = m->line_number_from_bci(bci);
1536 }
1537
1538 write_header(writer, HPROF_FRAME, 4*oopSize + 2*sizeof(u4));
1539 writer->write_id(frame_serial_num); // frame serial number
1540 writer->write_symbolID(m->name()); // method's name
1541 writer->write_symbolID(m->signature()); // method's signature
1542
1543 assert(m->method_holder()->is_instance_klass(), "not InstanceKlass")do { if (!(m->method_holder()->is_instance_klass())) { (
*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1543, "assert(" "m->method_holder()->is_instance_klass()"
") failed", "not InstanceKlass"); ::breakpoint(); } } while (
0)
;
1544 writer->write_symbolID(m->method_holder()->source_file_name()); // source file name
1545 writer->write_u4(class_serial_num); // class serial number
1546 writer->write_u4((u4) line_number); // line number
1547}
1548
1549
1550// Support class used to generate HPROF_UTF8 records from the entries in the
1551// SymbolTable.
1552
1553class SymbolTableDumper : public SymbolClosure {
1554 private:
1555 AbstractDumpWriter* _writer;
1556 AbstractDumpWriter* writer() const { return _writer; }
1557 public:
1558 SymbolTableDumper(AbstractDumpWriter* writer) { _writer = writer; }
1559 void do_symbol(Symbol** p);
1560};
1561
1562void SymbolTableDumper::do_symbol(Symbol** p) {
1563 ResourceMark rm;
1564 Symbol* sym = *p;
1565 int len = sym->utf8_length();
1566 if (len > 0) {
1567 char* s = sym->as_utf8();
1568 DumperSupport::write_header(writer(), HPROF_UTF8, oopSize + len);
1569 writer()->write_symbolID(sym);
1570 writer()->write_raw(s, len);
1571 }
1572}
1573
1574// Support class used to generate HPROF_GC_ROOT_JNI_LOCAL records
1575
1576class JNILocalsDumper : public OopClosure {
1577 private:
1578 AbstractDumpWriter* _writer;
1579 u4 _thread_serial_num;
1580 int _frame_num;
1581 AbstractDumpWriter* writer() const { return _writer; }
1582 public:
1583 JNILocalsDumper(AbstractDumpWriter* writer, u4 thread_serial_num) {
1584 _writer = writer;
1585 _thread_serial_num = thread_serial_num;
1586 _frame_num = -1; // default - empty stack
1587 }
1588 void set_frame_number(int n) { _frame_num = n; }
1589 void do_oop(oop* obj_p);
1590 void do_oop(narrowOop* obj_p) { ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here(
"/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1590); ::breakpoint(); } while (0)
; }
1591};
1592
1593
1594void JNILocalsDumper::do_oop(oop* obj_p) {
1595 // ignore null handles
1596 oop o = *obj_p;
1597 if (o != NULL__null) {
1598 u4 size = 1 + sizeof(address) + 4 + 4;
1599 writer()->start_sub_record(HPROF_GC_ROOT_JNI_LOCAL, size);
1600 writer()->write_objectID(o);
1601 writer()->write_u4(_thread_serial_num);
1602 writer()->write_u4((u4)_frame_num);
1603 writer()->end_sub_record();
1604 }
1605}
1606
1607
1608// Support class used to generate HPROF_GC_ROOT_JNI_GLOBAL records
1609
1610class JNIGlobalsDumper : public OopClosure {
1611 private:
1612 AbstractDumpWriter* _writer;
1613 AbstractDumpWriter* writer() const { return _writer; }
1614
1615 public:
1616 JNIGlobalsDumper(AbstractDumpWriter* writer) {
1617 _writer = writer;
1618 }
1619 void do_oop(oop* obj_p);
1620 void do_oop(narrowOop* obj_p) { ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here(
"/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1620); ::breakpoint(); } while (0)
; }
1621};
1622
1623void JNIGlobalsDumper::do_oop(oop* obj_p) {
1624 oop o = NativeAccess<AS_NO_KEEPALIVE>::oop_load(obj_p);
1625
1626 // ignore these
1627 if (o == NULL__null) return;
1628 // we ignore global ref to symbols and other internal objects
1629 if (o->is_instance() || o->is_objArray() || o->is_typeArray()) {
1630 u4 size = 1 + 2 * sizeof(address);
1631 writer()->start_sub_record(HPROF_GC_ROOT_JNI_GLOBAL, size);
1632 writer()->write_objectID(o);
1633 writer()->write_objectID((oopDesc*)obj_p); // global ref ID
1634 writer()->end_sub_record();
1635 }
1636};
1637
1638// Support class used to generate HPROF_GC_ROOT_STICKY_CLASS records
1639
1640class StickyClassDumper : public KlassClosure {
1641 private:
1642 AbstractDumpWriter* _writer;
1643 AbstractDumpWriter* writer() const { return _writer; }
1644 public:
1645 StickyClassDumper(AbstractDumpWriter* writer) {
1646 _writer = writer;
1647 }
1648 void do_klass(Klass* k) {
1649 if (k->is_instance_klass()) {
1650 InstanceKlass* ik = InstanceKlass::cast(k);
1651 u4 size = 1 + sizeof(address);
1652 writer()->start_sub_record(HPROF_GC_ROOT_STICKY_CLASS, size);
1653 writer()->write_classID(ik);
1654 writer()->end_sub_record();
1655 }
1656 }
1657};
1658
1659// Large object heap dump support.
1660// To avoid memory consumption, when dumping large objects such as huge array and
1661// large objects whose size are larger than LARGE_OBJECT_DUMP_THRESHOLD, the scanned
1662// partial object/array data will be sent to the backend directly instead of caching
1663// the whole object/array in the internal buffer.
1664// The HeapDumpLargeObjectList is used to save the large object when dumper scans
1665// the heap. The large objects could be added (push) parallelly by multiple dumpers,
1666// But they will be removed (popped) serially only by the VM thread.
1667class HeapDumpLargeObjectList : public CHeapObj<mtInternal> {
1668 private:
1669 class HeapDumpLargeObjectListElem : public CHeapObj<mtInternal> {
1670 public:
1671 HeapDumpLargeObjectListElem(oop obj) : _obj(obj), _next(NULL__null) { }
1672 oop _obj;
1673 HeapDumpLargeObjectListElem* _next;
1674 };
1675
1676 volatile HeapDumpLargeObjectListElem* _head;
1677
1678 public:
1679 HeapDumpLargeObjectList() : _head(NULL__null) { }
1680
1681 void atomic_push(oop obj) {
1682 assert (obj != NULL, "sanity check")do { if (!(obj != __null)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1682, "assert(" "obj != __null" ") failed", "sanity check")
; ::breakpoint(); } } while (0)
;
1683 HeapDumpLargeObjectListElem* entry = new HeapDumpLargeObjectListElem(obj);
1684 if (entry == NULL__null) {
1685 warning("failed to allocate element for large object list");
1686 return;
1687 }
1688 assert (entry->_obj != NULL, "sanity check")do { if (!(entry->_obj != __null)) { (*g_assert_poison) = 'X'
;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1688, "assert(" "entry->_obj != __null" ") failed", "sanity check"
); ::breakpoint(); } } while (0)
;
1689 while (true) {
1690 volatile HeapDumpLargeObjectListElem* old_head = Atomic::load_acquire(&_head);
1691 HeapDumpLargeObjectListElem* new_head = entry;
1692 if (Atomic::cmpxchg(&_head, old_head, new_head) == old_head) {
1693 // successfully push
1694 new_head->_next = (HeapDumpLargeObjectListElem*)old_head;
1695 return;
1696 }
1697 }
1698 }
1699
1700 oop pop() {
1701 if (_head == NULL__null) {
1702 return NULL__null;
1703 }
1704 HeapDumpLargeObjectListElem* entry = (HeapDumpLargeObjectListElem*)_head;
1705 _head = _head->_next;
1706 assert (entry != NULL, "illegal larger object list entry")do { if (!(entry != __null)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1706, "assert(" "entry != __null" ") failed", "illegal larger object list entry"
); ::breakpoint(); } } while (0)
;
1707 oop ret = entry->_obj;
1708 delete entry;
1709 assert (ret != NULL, "illegal oop pointer")do { if (!(ret != __null)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1709, "assert(" "ret != __null" ") failed", "illegal oop pointer"
); ::breakpoint(); } } while (0)
;
1710 return ret;
1711 }
1712
1713 void drain(ObjectClosure* cl) {
1714 while (_head != NULL__null) {
1715 cl->do_object(pop());
1716 }
1717 }
1718
1719 bool is_empty() {
1720 return _head == NULL__null;
1721 }
1722
1723 static const size_t LargeObjectSizeThreshold = 1 << 20; // 1 MB
1724};
1725
1726class VM_HeapDumper;
1727
1728// Support class using when iterating over the heap.
1729class HeapObjectDumper : public ObjectClosure {
1730 private:
1731 AbstractDumpWriter* _writer;
1732 HeapDumpLargeObjectList* _list;
1733
1734 AbstractDumpWriter* writer() { return _writer; }
1735 bool is_large(oop o);
1736 public:
1737 HeapObjectDumper(AbstractDumpWriter* writer, HeapDumpLargeObjectList* list = NULL__null) {
1738 _writer = writer;
1739 _list = list;
1740 }
1741
1742 // called for each object in the heap
1743 void do_object(oop o);
1744};
1745
1746void HeapObjectDumper::do_object(oop o) {
1747 // skip classes as these emitted as HPROF_GC_CLASS_DUMP records
1748 if (o->klass() == vmClasses::Class_klass()) {
1749 if (!java_lang_Class::is_primitive(o)) {
1750 return;
1751 }
1752 }
1753
1754 if (DumperSupport::mask_dormant_archived_object(o) == NULL__null) {
1755 log_debug(cds, heap)(!(LogImpl<(LogTag::_cds), (LogTag::_heap), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)
>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag
::_cds), (LogTag::_heap), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel
::Debug>
("skipped dormant archived object " INTPTR_FORMAT"0x%016" "l" "x" " (%s)", p2i(o), o->klass()->external_name());
1756 return;
1757 }
1758
1759 // If large object list exists and it is large object/array,
1760 // add oop into the list and skip scan. VM thread will process it later.
1761 if (_list != NULL__null && is_large(o)) {
1762 _list->atomic_push(o);
1763 return;
1764 }
1765
1766 if (o->is_instance()) {
1767 // create a HPROF_GC_INSTANCE record for each object
1768 DumperSupport::dump_instance(writer(), o);
1769 } else if (o->is_objArray()) {
1770 // create a HPROF_GC_OBJ_ARRAY_DUMP record for each object array
1771 DumperSupport::dump_object_array(writer(), objArrayOop(o));
1772 } else if (o->is_typeArray()) {
1773 // create a HPROF_GC_PRIM_ARRAY_DUMP record for each type array
1774 DumperSupport::dump_prim_array(writer(), typeArrayOop(o));
1775 }
1776}
1777
1778bool HeapObjectDumper::is_large(oop o) {
1779 size_t size = 0;
1780 if (o->is_instance()) {
1781 // Use o->size() * 8 as the upper limit of instance size to avoid iterating static fields
1782 size = o->size() * 8;
1783 } else if (o->is_objArray()) {
1784 objArrayOop array = objArrayOop(o);
1785 BasicType type = ArrayKlass::cast(array->klass())->element_type();
1786 assert(type >= T_BOOLEAN && type <= T_OBJECT, "invalid array element type")do { if (!(type >= T_BOOLEAN && type <= T_OBJECT
)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1786, "assert(" "type >= T_BOOLEAN && type <= T_OBJECT"
") failed", "invalid array element type"); ::breakpoint(); }
} while (0)
;
1787 int length = array->length();
1788 int type_size = sizeof(address);
1789 size = (size_t)length * type_size;
1790 } else if (o->is_typeArray()) {
1791 typeArrayOop array = typeArrayOop(o);
1792 BasicType type = ArrayKlass::cast(array->klass())->element_type();
1793 assert(type >= T_BOOLEAN && type <= T_OBJECT, "invalid array element type")do { if (!(type >= T_BOOLEAN && type <= T_OBJECT
)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1793, "assert(" "type >= T_BOOLEAN && type <= T_OBJECT"
") failed", "invalid array element type"); ::breakpoint(); }
} while (0)
;
1794 int length = array->length();
1795 int type_size = type2aelembytes(type);
1796 size = (size_t)length * type_size;
1797 }
1798 return size > HeapDumpLargeObjectList::LargeObjectSizeThreshold;
1799}
1800
1801// The dumper controller for parallel heap dump
1802class DumperController : public CHeapObj<mtInternal> {
1803 private:
1804 bool _started;
1805 Monitor* _lock;
1806 uint _dumper_number;
1807 uint _complete_number;
1808
1809 public:
1810 DumperController(uint number) :
1811 _started(false),
1812 _lock(new (std::nothrow) PaddedMonitor(Mutex::safepoint, "DumperController_lock")),
1813 _dumper_number(number),
1814 _complete_number(0) { }
1815
1816 ~DumperController() { delete _lock; }
1817
1818 void wait_for_start_signal() {
1819 MonitorLocker ml(_lock, Mutex::_no_safepoint_check_flag);
1820 while (_started == false) {
1821 ml.wait();
1822 }
1823 assert(_started == true, "dumper woke up with wrong state")do { if (!(_started == true)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1823, "assert(" "_started == true" ") failed", "dumper woke up with wrong state"
); ::breakpoint(); } } while (0)
;
1824 }
1825
1826 void start_dump() {
1827 assert (_started == false, "start dump with wrong state")do { if (!(_started == false)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1827, "assert(" "_started == false" ") failed", "start dump with wrong state"
); ::breakpoint(); } } while (0)
;
1828 MonitorLocker ml(_lock, Mutex::_no_safepoint_check_flag);
1829 _started = true;
1830 ml.notify_all();
1831 }
1832
1833 void dumper_complete() {
1834 assert (_started == true, "dumper complete with wrong state")do { if (!(_started == true)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1834, "assert(" "_started == true" ") failed", "dumper complete with wrong state"
); ::breakpoint(); } } while (0)
;
1835 MonitorLocker ml(_lock, Mutex::_no_safepoint_check_flag);
1836 _complete_number++;
1837 ml.notify();
1838 }
1839
1840 void wait_all_dumpers_complete() {
1841 assert (_started == true, "wrong state when wait for dumper complete")do { if (!(_started == true)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1841, "assert(" "_started == true" ") failed", "wrong state when wait for dumper complete"
); ::breakpoint(); } } while (0)
;
1842 MonitorLocker ml(_lock, Mutex::_no_safepoint_check_flag);
1843 while (_complete_number != _dumper_number) {
1844 ml.wait();
1845 }
1846 _started = false;
1847 }
1848};
1849
1850// The VM operation that performs the heap dump
1851class VM_HeapDumper : public VM_GC_Operation, public WorkerTask {
1852 private:
1853 static VM_HeapDumper* _global_dumper;
1854 static DumpWriter* _global_writer;
1855 DumpWriter* _local_writer;
1856 JavaThread* _oome_thread;
1857 Method* _oome_constructor;
1858 bool _gc_before_heap_dump;
1859 GrowableArray<Klass*>* _klass_map;
1860 ThreadStackTrace** _stack_traces;
1861 int _num_threads;
1862 // parallel heap dump support
1863 uint _num_dumper_threads;
1864 uint _num_writer_threads;
1865 DumperController* _dumper_controller;
1866 ParallelObjectIterator* _poi;
1867 HeapDumpLargeObjectList* _large_object_list;
1868
1869 // VMDumperType is for thread that dumps both heap and non-heap data.
1870 static const size_t VMDumperType = 0;
1871 static const size_t WriterType = 1;
1872 static const size_t DumperType = 2;
1873 // worker id of VMDumper thread.
1874 static const size_t VMDumperWorkerId = 0;
1875
1876 size_t get_worker_type(uint worker_id) {
1877 assert(_num_writer_threads >= 1, "Must be at least one writer")do { if (!(_num_writer_threads >= 1)) { (*g_assert_poison)
= 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1877, "assert(" "_num_writer_threads >= 1" ") failed", "Must be at least one writer"
); ::breakpoint(); } } while (0)
;
1878 // worker id of VMDumper that dump heap and non-heap data
1879 if (worker_id == VMDumperWorkerId) {
1880 return VMDumperType;
1881 }
1882
1883 // worker id of dumper starts from 1, which only dump heap datar
1884 if (worker_id < _num_dumper_threads) {
1885 return DumperType;
1886 }
1887
1888 // worker id of writer starts from _num_dumper_threads
1889 return WriterType;
1890 }
1891
1892 void prepare_parallel_dump(uint num_total) {
1893 assert (_dumper_controller == NULL, "dumper controller must be NULL")do { if (!(_dumper_controller == __null)) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1893, "assert(" "_dumper_controller == __null" ") failed", "dumper controller must be NULL"
); ::breakpoint(); } } while (0)
;
1894 assert (num_total > 0, "active workers number must >= 1")do { if (!(num_total > 0)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1894, "assert(" "num_total > 0" ") failed", "active workers number must >= 1"
); ::breakpoint(); } } while (0)
;
1895 // Dumper threads number must not be larger than active workers number.
1896 if (num_total < _num_dumper_threads) {
1897 _num_dumper_threads = num_total - 1;
1898 }
1899 // Calculate dumper and writer threads number.
1900 _num_writer_threads = num_total - _num_dumper_threads;
1901 // If dumper threads number is 1, only the VMThread works as a dumper.
1902 // If dumper threads number is equal to active workers, need at lest one worker thread as writer.
1903 if (_num_dumper_threads > 0 && _num_writer_threads == 0) {
1904 _num_writer_threads = 1;
1905 _num_dumper_threads = num_total - _num_writer_threads;
1906 }
1907 // Prepare parallel writer.
1908 if (_num_dumper_threads > 1) {
1909 ParDumpWriter::before_work();
1910 // Number of dumper threads that only iterate heap.
1911 uint _heap_only_dumper_threads = _num_dumper_threads - 1 /* VMDumper thread */;
1912 _dumper_controller = new (std::nothrow) DumperController(_heap_only_dumper_threads);
1913 }
1914 }
1915
1916 void finish_parallel_dump() {
1917 if (_num_dumper_threads > 1) {
1918 ParDumpWriter::after_work();
1919 }
1920 }
1921
1922 // accessors and setters
1923 static VM_HeapDumper* dumper() { assert(_global_dumper != NULL, "Error")do { if (!(_global_dumper != __null)) { (*g_assert_poison) = 'X'
;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1923, "assert(" "_global_dumper != __null" ") failed", "Error"
); ::breakpoint(); } } while (0)
; return _global_dumper; }
1924 static DumpWriter* writer() { assert(_global_writer != NULL, "Error")do { if (!(_global_writer != __null)) { (*g_assert_poison) = 'X'
;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1924, "assert(" "_global_writer != __null" ") failed", "Error"
); ::breakpoint(); } } while (0)
; return _global_writer; }
1925 void set_global_dumper() {
1926 assert(_global_dumper == NULL, "Error")do { if (!(_global_dumper == __null)) { (*g_assert_poison) = 'X'
;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1926, "assert(" "_global_dumper == __null" ") failed", "Error"
); ::breakpoint(); } } while (0)
;
1927 _global_dumper = this;
1928 }
1929 void set_global_writer() {
1930 assert(_global_writer == NULL, "Error")do { if (!(_global_writer == __null)) { (*g_assert_poison) = 'X'
;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1930, "assert(" "_global_writer == __null" ") failed", "Error"
); ::breakpoint(); } } while (0)
;
1931 _global_writer = _local_writer;
1932 }
1933 void clear_global_dumper() { _global_dumper = NULL__null; }
1934 void clear_global_writer() { _global_writer = NULL__null; }
1935
1936 bool skip_operation() const;
1937
1938 // writes a HPROF_LOAD_CLASS record
1939 class ClassesDo;
1940 static void do_load_class(Klass* k);
1941
1942 // writes a HPROF_GC_CLASS_DUMP record for the given class
1943 // (and each array class too)
1944 static void do_class_dump(Klass* k);
1945
1946 // writes a HPROF_GC_CLASS_DUMP records for a given basic type
1947 // array (and each multi-dimensional array too)
1948 static void do_basic_type_array_class_dump(Klass* k);
1949
1950 // HPROF_GC_ROOT_THREAD_OBJ records
1951 int do_thread(JavaThread* thread, u4 thread_serial_num);
1952 void do_threads();
1953
1954 void add_class_serial_number(Klass* k, int serial_num) {
1955 _klass_map->at_put_grow(serial_num, k);
1956 }
1957
1958 // HPROF_TRACE and HPROF_FRAME records
1959 void dump_stack_traces();
1960
1961 // large objects
1962 void dump_large_objects(ObjectClosure* writer);
1963
1964 public:
1965 VM_HeapDumper(DumpWriter* writer, bool gc_before_heap_dump, bool oome, uint num_dump_threads) :
1966 VM_GC_Operation(0 /* total collections, dummy, ignored */,
1967 GCCause::_heap_dump /* GC Cause */,
1968 0 /* total full collections, dummy, ignored */,
1969 gc_before_heap_dump),
1970 WorkerTask("dump heap") {
1971 _local_writer = writer;
1972 _gc_before_heap_dump = gc_before_heap_dump;
1973 _klass_map = new (ResourceObj::C_HEAP, mtServiceability) GrowableArray<Klass*>(INITIAL_CLASS_COUNT, mtServiceability);
1974 _stack_traces = NULL__null;
1975 _num_threads = 0;
1976 _num_dumper_threads = num_dump_threads;
1977 _dumper_controller = NULL__null;
1978 _poi = NULL__null;
1979 _large_object_list = new (std::nothrow) HeapDumpLargeObjectList();
1980 if (oome) {
1981 assert(!Thread::current()->is_VM_thread(), "Dump from OutOfMemoryError cannot be called by the VMThread")do { if (!(!Thread::current()->is_VM_thread())) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 1981, "assert(" "!Thread::current()->is_VM_thread()" ") failed"
, "Dump from OutOfMemoryError cannot be called by the VMThread"
); ::breakpoint(); } } while (0)
;
1982 // get OutOfMemoryError zero-parameter constructor
1983 InstanceKlass* oome_ik = vmClasses::OutOfMemoryError_klass();
1984 _oome_constructor = oome_ik->find_method(vmSymbols::object_initializer_name(),
1985 vmSymbols::void_method_signature());
1986 // get thread throwing OOME when generating the heap dump at OOME
1987 _oome_thread = JavaThread::current();
1988 } else {
1989 _oome_thread = NULL__null;
1990 _oome_constructor = NULL__null;
1991 }
1992 }
1993
1994 ~VM_HeapDumper() {
1995 if (_stack_traces != NULL__null) {
1996 for (int i=0; i < _num_threads; i++) {
1997 delete _stack_traces[i];
1998 }
1999 FREE_C_HEAP_ARRAY(ThreadStackTrace*, _stack_traces)FreeHeap((char*)(_stack_traces));
2000 }
2001 if (_dumper_controller != NULL__null) {
2002 delete _dumper_controller;
2003 _dumper_controller = NULL__null;
2004 }
2005 delete _klass_map;
2006 delete _large_object_list;
2007 }
2008
2009 VMOp_Type type() const { return VMOp_HeapDumper; }
2010 void doit();
2011 void work(uint worker_id);
2012};
2013
2014VM_HeapDumper* VM_HeapDumper::_global_dumper = NULL__null;
2015DumpWriter* VM_HeapDumper::_global_writer = NULL__null;
2016
2017bool VM_HeapDumper::skip_operation() const {
2018 return false;
2019}
2020
2021// fixes up the current dump record and writes HPROF_HEAP_DUMP_END record
2022void DumperSupport::end_of_dump(AbstractDumpWriter* writer) {
2023 writer->finish_dump_segment();
2024
2025 writer->write_u1(HPROF_HEAP_DUMP_END);
2026 writer->write_u4(0);
2027 writer->write_u4(0);
2028}
2029
2030// writes a HPROF_LOAD_CLASS record for the class (and each of its
2031// array classes)
2032void VM_HeapDumper::do_load_class(Klass* k) {
2033 static u4 class_serial_num = 0;
2034
2035 // len of HPROF_LOAD_CLASS record
2036 u4 remaining = 2*oopSize + 2*sizeof(u4);
2037
2038 // write a HPROF_LOAD_CLASS for the class and each array class
2039 do {
2040 DumperSupport::write_header(writer(), HPROF_LOAD_CLASS, remaining);
2041
2042 // class serial number is just a number
2043 writer()->write_u4(++class_serial_num);
2044
2045 // class ID
2046 Klass* klass = k;
2047 writer()->write_classID(klass);
2048
2049 // add the Klass* and class serial number pair
2050 dumper()->add_class_serial_number(klass, class_serial_num);
2051
2052 writer()->write_u4(STACK_TRACE_ID);
2053
2054 // class name ID
2055 Symbol* name = klass->name();
2056 writer()->write_symbolID(name);
2057
2058 // write a LOAD_CLASS record for the array type (if it exists)
2059 k = klass->array_klass_or_null();
2060 } while (k != NULL__null);
2061}
2062
2063// writes a HPROF_GC_CLASS_DUMP record for the given class
2064void VM_HeapDumper::do_class_dump(Klass* k) {
2065 if (k->is_instance_klass()) {
2066 DumperSupport::dump_class_and_array_classes(writer(), k);
2067 }
2068}
2069
2070// writes a HPROF_GC_CLASS_DUMP records for a given basic type
2071// array (and each multi-dimensional array too)
2072void VM_HeapDumper::do_basic_type_array_class_dump(Klass* k) {
2073 DumperSupport::dump_basic_type_array_class(writer(), k);
2074}
2075
2076// Walk the stack of the given thread.
2077// Dumps a HPROF_GC_ROOT_JAVA_FRAME record for each local
2078// Dumps a HPROF_GC_ROOT_JNI_LOCAL record for each JNI local
2079//
2080// It returns the number of Java frames in this thread stack
2081int VM_HeapDumper::do_thread(JavaThread* java_thread, u4 thread_serial_num) {
2082 JNILocalsDumper blk(writer(), thread_serial_num);
2083
2084 oop threadObj = java_thread->threadObj();
2085 assert(threadObj != NULL, "sanity check")do { if (!(threadObj != __null)) { (*g_assert_poison) = 'X';;
report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 2085, "assert(" "threadObj != __null" ") failed", "sanity check"
); ::breakpoint(); } } while (0)
;
2086
2087 int stack_depth = 0;
2088 if (java_thread->has_last_Java_frame()) {
2089
2090 // vframes are resource allocated
2091 Thread* current_thread = Thread::current();
2092 ResourceMark rm(current_thread);
2093 HandleMark hm(current_thread);
2094
2095 RegisterMap reg_map(java_thread);
2096 frame f = java_thread->last_frame();
2097 vframe* vf = vframe::new_vframe(&f, &reg_map, java_thread);
2098 frame* last_entry_frame = NULL__null;
2099 int extra_frames = 0;
2100
2101 if (java_thread == _oome_thread && _oome_constructor != NULL__null) {
2102 extra_frames++;
2103 }
2104 while (vf != NULL__null) {
2105 blk.set_frame_number(stack_depth);
2106 if (vf->is_java_frame()) {
2107
2108 // java frame (interpreted, compiled, ...)
2109 javaVFrame *jvf = javaVFrame::cast(vf);
2110 if (!(jvf->method()->is_native())) {
2111 StackValueCollection* locals = jvf->locals();
2112 for (int slot=0; slot<locals->size(); slot++) {
2113 if (locals->at(slot)->type() == T_OBJECT) {
2114 oop o = locals->obj_at(slot)();
2115
2116 if (o != NULL__null) {
2117 u4 size = 1 + sizeof(address) + 4 + 4;
2118 writer()->start_sub_record(HPROF_GC_ROOT_JAVA_FRAME, size);
2119 writer()->write_objectID(o);
2120 writer()->write_u4(thread_serial_num);
2121 writer()->write_u4((u4) (stack_depth + extra_frames));
2122 writer()->end_sub_record();
2123 }
2124 }
2125 }
2126 StackValueCollection *exprs = jvf->expressions();
2127 for(int index = 0; index < exprs->size(); index++) {
2128 if (exprs->at(index)->type() == T_OBJECT) {
2129 oop o = exprs->obj_at(index)();
2130 if (o != NULL__null) {
2131 u4 size = 1 + sizeof(address) + 4 + 4;
2132 writer()->start_sub_record(HPROF_GC_ROOT_JAVA_FRAME, size);
2133 writer()->write_objectID(o);
2134 writer()->write_u4(thread_serial_num);
2135 writer()->write_u4((u4) (stack_depth + extra_frames));
2136 writer()->end_sub_record();
2137 }
2138 }
2139 }
2140 } else {
2141 // native frame
2142 if (stack_depth == 0) {
2143 // JNI locals for the top frame.
2144 java_thread->active_handles()->oops_do(&blk);
2145 } else {
2146 if (last_entry_frame != NULL__null) {
2147 // JNI locals for the entry frame
2148 assert(last_entry_frame->is_entry_frame(), "checking")do { if (!(last_entry_frame->is_entry_frame())) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 2148, "assert(" "last_entry_frame->is_entry_frame()" ") failed"
, "checking"); ::breakpoint(); } } while (0)
;
2149 last_entry_frame->entry_frame_call_wrapper()->handles()->oops_do(&blk);
2150 }
2151 }
2152 }
2153 // increment only for Java frames
2154 stack_depth++;
2155 last_entry_frame = NULL__null;
2156
2157 } else {
2158 // externalVFrame - if it's an entry frame then report any JNI locals
2159 // as roots when we find the corresponding native javaVFrame
2160 frame* fr = vf->frame_pointer();
2161 assert(fr != NULL, "sanity check")do { if (!(fr != __null)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 2161, "assert(" "fr != __null" ") failed", "sanity check");
::breakpoint(); } } while (0)
;
2162 if (fr->is_entry_frame()) {
2163 last_entry_frame = fr;
2164 }
2165 }
2166 vf = vf->sender();
2167 }
2168 } else {
2169 // no last java frame but there may be JNI locals
2170 java_thread->active_handles()->oops_do(&blk);
2171 }
2172 return stack_depth;
2173}
2174
2175
2176// write a HPROF_GC_ROOT_THREAD_OBJ record for each java thread. Then walk
2177// the stack so that locals and JNI locals are dumped.
2178void VM_HeapDumper::do_threads() {
2179 for (int i=0; i < _num_threads; i++) {
2180 JavaThread* thread = _stack_traces[i]->thread();
2181 oop threadObj = thread->threadObj();
2182 u4 thread_serial_num = i+1;
2183 u4 stack_serial_num = thread_serial_num + STACK_TRACE_ID;
2184 u4 size = 1 + sizeof(address) + 4 + 4;
2185 writer()->start_sub_record(HPROF_GC_ROOT_THREAD_OBJ, size);
2186 writer()->write_objectID(threadObj);
2187 writer()->write_u4(thread_serial_num); // thread number
2188 writer()->write_u4(stack_serial_num); // stack trace serial number
2189 writer()->end_sub_record();
2190 int num_frames = do_thread(thread, thread_serial_num);
2191 assert(num_frames == _stack_traces[i]->get_stack_depth(),do { if (!(num_frames == _stack_traces[i]->get_stack_depth
())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 2192, "assert(" "num_frames == _stack_traces[i]->get_stack_depth()"
") failed", "total number of Java frames not matched"); ::breakpoint
(); } } while (0)
2192 "total number of Java frames not matched")do { if (!(num_frames == _stack_traces[i]->get_stack_depth
())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 2192, "assert(" "num_frames == _stack_traces[i]->get_stack_depth()"
") failed", "total number of Java frames not matched"); ::breakpoint
(); } } while (0)
;
2193 }
2194}
2195
2196
2197// The VM operation that dumps the heap. The dump consists of the following
2198// records:
2199//
2200// HPROF_HEADER
2201// [HPROF_UTF8]*
2202// [HPROF_LOAD_CLASS]*
2203// [[HPROF_FRAME]*|HPROF_TRACE]*
2204// [HPROF_GC_CLASS_DUMP]*
2205// [HPROF_HEAP_DUMP_SEGMENT]*
2206// HPROF_HEAP_DUMP_END
2207//
2208// The HPROF_TRACE records represent the stack traces where the heap dump
2209// is generated and a "dummy trace" record which does not include
2210// any frames. The dummy trace record is used to be referenced as the
2211// unknown object alloc site.
2212//
2213// Each HPROF_HEAP_DUMP_SEGMENT record has a length followed by sub-records.
2214// To allow the heap dump be generated in a single pass we remember the position
2215// of the dump length and fix it up after all sub-records have been written.
2216// To generate the sub-records we iterate over the heap, writing
2217// HPROF_GC_INSTANCE_DUMP, HPROF_GC_OBJ_ARRAY_DUMP, and HPROF_GC_PRIM_ARRAY_DUMP
2218// records as we go. Once that is done we write records for some of the GC
2219// roots.
2220
2221void VM_HeapDumper::doit() {
2222
2223 CollectedHeap* ch = Universe::heap();
2224
2225 ch->ensure_parsability(false); // must happen, even if collection does
2226 // not happen (e.g. due to GCLocker)
2227
2228 if (_gc_before_heap_dump) {
2229 if (GCLocker::is_active()) {
2230 warning("GC locker is held; pre-heapdump GC was skipped");
2231 } else {
2232 ch->collect_as_vm_thread(GCCause::_heap_dump);
2233 }
2234 }
2235
2236 // At this point we should be the only dumper active, so
2237 // the following should be safe.
2238 set_global_dumper();
2239 set_global_writer();
2240
2241 WorkerThreads* workers = ch->safepoint_workers();
2242
2243 if (workers == NULL__null) {
2244 // Use serial dump, set dumper threads and writer threads number to 1.
2245 _num_dumper_threads=1;
2246 _num_writer_threads=1;
2247 work(0);
2248 } else {
2249 prepare_parallel_dump(workers->active_workers());
2250 if (_num_dumper_threads > 1) {
2251 ParallelObjectIterator poi(_num_dumper_threads);
2252 _poi = &poi;
2253 workers->run_task(this);
2254 _poi = NULL__null;
2255 } else {
2256 workers->run_task(this);
2257 }
2258 finish_parallel_dump();
2259 }
2260
2261 // Now we clear the global variables, so that a future dumper can run.
2262 clear_global_dumper();
2263 clear_global_writer();
2264}
2265
2266void VM_HeapDumper::work(uint worker_id) {
2267 if (worker_id != 0) {
2268 if (get_worker_type(worker_id) == WriterType) {
2269 writer()->writer_loop();
2270 return;
2271 }
2272 if (_num_dumper_threads > 1 && get_worker_type(worker_id) == DumperType) {
2273 _dumper_controller->wait_for_start_signal();
2274 }
2275 } else {
2276 // The worker 0 on all non-heap data dumping and part of heap iteration.
2277 // Write the file header - we always use 1.0.2
2278 const char* header = "JAVA PROFILE 1.0.2";
2279
2280 // header is few bytes long - no chance to overflow int
2281 writer()->write_raw(header, strlen(header) + 1); // NUL terminated
2282 writer()->write_u4(oopSize);
2283 // timestamp is current time in ms
2284 writer()->write_u8(os::javaTimeMillis());
2285 // HPROF_UTF8 records
2286 SymbolTableDumper sym_dumper(writer());
2287 SymbolTable::symbols_do(&sym_dumper);
2288
2289 // write HPROF_LOAD_CLASS records
2290 {
2291 LockedClassesDo locked_load_classes(&do_load_class);
2292 ClassLoaderDataGraph::classes_do(&locked_load_classes);
2293 }
2294 Universe::basic_type_classes_do(&do_load_class);
2295
2296 // write HPROF_FRAME and HPROF_TRACE records
2297 // this must be called after _klass_map is built when iterating the classes above.
2298 dump_stack_traces();
2299
2300 // Writes HPROF_GC_CLASS_DUMP records
2301 {
2302 LockedClassesDo locked_dump_class(&do_class_dump);
2303 ClassLoaderDataGraph::classes_do(&locked_dump_class);
2304 }
2305 Universe::basic_type_classes_do(&do_basic_type_array_class_dump);
2306
2307 // HPROF_GC_ROOT_THREAD_OBJ + frames + jni locals
2308 do_threads();
2309
2310 // HPROF_GC_ROOT_JNI_GLOBAL
2311 JNIGlobalsDumper jni_dumper(writer());
2312 JNIHandles::oops_do(&jni_dumper);
2313 // technically not jni roots, but global roots
2314 // for things like preallocated throwable backtraces
2315 Universe::vm_global()->oops_do(&jni_dumper);
2316 // HPROF_GC_ROOT_STICKY_CLASS
2317 // These should be classes in the NULL class loader data, and not all classes
2318 // if !ClassUnloading
2319 StickyClassDumper class_dumper(writer());
2320 ClassLoaderData::the_null_class_loader_data()->classes_do(&class_dumper);
2321 }
2322 // writes HPROF_GC_INSTANCE_DUMP records.
2323 // After each sub-record is written check_segment_length will be invoked
2324 // to check if the current segment exceeds a threshold. If so, a new
2325 // segment is started.
2326 // The HPROF_GC_CLASS_DUMP and HPROF_GC_INSTANCE_DUMP are the vast bulk
2327 // of the heap dump.
2328 if (_num_dumper_threads <= 1) {
2329 HeapObjectDumper obj_dumper(writer());
2330 Universe::heap()->object_iterate(&obj_dumper);
2331 } else {
2332 assert(get_worker_type(worker_id) == DumperTypedo { if (!(get_worker_type(worker_id) == DumperType || get_worker_type
(worker_id) == VMDumperType)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 2334, "assert(" "get_worker_type(worker_id) == DumperType || get_worker_type(worker_id) == VMDumperType"
") failed", "must be dumper thread to do heap iteration"); ::
breakpoint(); } } while (0)
2333 || get_worker_type(worker_id) == VMDumperType,do { if (!(get_worker_type(worker_id) == DumperType || get_worker_type
(worker_id) == VMDumperType)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 2334, "assert(" "get_worker_type(worker_id) == DumperType || get_worker_type(worker_id) == VMDumperType"
") failed", "must be dumper thread to do heap iteration"); ::
breakpoint(); } } while (0)
2334 "must be dumper thread to do heap iteration")do { if (!(get_worker_type(worker_id) == DumperType || get_worker_type
(worker_id) == VMDumperType)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 2334, "assert(" "get_worker_type(worker_id) == DumperType || get_worker_type(worker_id) == VMDumperType"
") failed", "must be dumper thread to do heap iteration"); ::
breakpoint(); } } while (0)
;
2335 if (get_worker_type(worker_id) == VMDumperType) {
2336 // Clear global writer's buffer.
2337 writer()->finish_dump_segment(true);
2338 // Notify dumpers to start heap iteration.
2339 _dumper_controller->start_dump();
2340 }
2341 // Heap iteration.
2342 {
2343 ParDumpWriter pw(writer());
2344 {
2345 HeapObjectDumper obj_dumper(&pw, _large_object_list);
2346 _poi->object_iterate(&obj_dumper, worker_id);
2347 }
2348
2349 if (get_worker_type(worker_id) == VMDumperType) {
2350 _dumper_controller->wait_all_dumpers_complete();
2351 // clear internal buffer;
2352 pw.finish_dump_segment(true);
2353 // refresh the global_writer's buffer and position;
2354 writer()->refresh();
2355 } else {
2356 pw.finish_dump_segment(true);
2357 _dumper_controller->dumper_complete();
2358 return;
2359 }
2360 }
2361 }
2362
2363 assert(get_worker_type(worker_id) == VMDumperType, "Heap dumper must be VMDumper")do { if (!(get_worker_type(worker_id) == VMDumperType)) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 2363, "assert(" "get_worker_type(worker_id) == VMDumperType"
") failed", "Heap dumper must be VMDumper"); ::breakpoint();
} } while (0)
;
2364 // Use writer() rather than ParDumpWriter to avoid memory consumption.
2365 HeapObjectDumper obj_dumper(writer());
2366 dump_large_objects(&obj_dumper);
2367 // Writes the HPROF_HEAP_DUMP_END record.
2368 DumperSupport::end_of_dump(writer());
2369 // We are done with writing. Release the worker threads.
2370 writer()->deactivate();
2371}
2372
2373void VM_HeapDumper::dump_stack_traces() {
2374 // write a HPROF_TRACE record without any frames to be referenced as object alloc sites
2375 DumperSupport::write_header(writer(), HPROF_TRACE, 3*sizeof(u4));
2376 writer()->write_u4((u4) STACK_TRACE_ID);
2377 writer()->write_u4(0); // thread number
2378 writer()->write_u4(0); // frame count
2379
2380 _stack_traces = NEW_C_HEAP_ARRAY(ThreadStackTrace*, Threads::number_of_threads(), mtInternal)(ThreadStackTrace**) (AllocateHeap((Threads::number_of_threads
()) * sizeof(ThreadStackTrace*), mtInternal))
;
2381 int frame_serial_num = 0;
2382 for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
2383 oop threadObj = thread->threadObj();
2384 if (threadObj != NULL__null && !thread->is_exiting() && !thread->is_hidden_from_external_view()) {
2385 // dump thread stack trace
2386 Thread* current_thread = Thread::current();
2387 ResourceMark rm(current_thread);
2388 HandleMark hm(current_thread);
2389
2390 ThreadStackTrace* stack_trace = new ThreadStackTrace(thread, false);
2391 stack_trace->dump_stack_at_safepoint(-1);
2392 _stack_traces[_num_threads++] = stack_trace;
2393
2394 // write HPROF_FRAME records for this thread's stack trace
2395 int depth = stack_trace->get_stack_depth();
2396 int thread_frame_start = frame_serial_num;
2397 int extra_frames = 0;
2398 // write fake frame that makes it look like the thread, which caused OOME,
2399 // is in the OutOfMemoryError zero-parameter constructor
2400 if (thread == _oome_thread && _oome_constructor != NULL__null) {
2401 int oome_serial_num = _klass_map->find(_oome_constructor->method_holder());
2402 // the class serial number starts from 1
2403 assert(oome_serial_num > 0, "OutOfMemoryError class not found")do { if (!(oome_serial_num > 0)) { (*g_assert_poison) = 'X'
;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 2403, "assert(" "oome_serial_num > 0" ") failed", "OutOfMemoryError class not found"
); ::breakpoint(); } } while (0)
;
2404 DumperSupport::dump_stack_frame(writer(), ++frame_serial_num, oome_serial_num,
2405 _oome_constructor, 0);
2406 extra_frames++;
2407 }
2408 for (int j=0; j < depth; j++) {
2409 StackFrameInfo* frame = stack_trace->stack_frame_at(j);
2410 Method* m = frame->method();
2411 int class_serial_num = _klass_map->find(m->method_holder());
2412 // the class serial number starts from 1
2413 assert(class_serial_num > 0, "class not found")do { if (!(class_serial_num > 0)) { (*g_assert_poison) = 'X'
;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 2413, "assert(" "class_serial_num > 0" ") failed", "class not found"
); ::breakpoint(); } } while (0)
;
2414 DumperSupport::dump_stack_frame(writer(), ++frame_serial_num, class_serial_num, m, frame->bci());
2415 }
2416 depth += extra_frames;
2417
2418 // write HPROF_TRACE record for one thread
2419 DumperSupport::write_header(writer(), HPROF_TRACE, 3*sizeof(u4) + depth*oopSize);
2420 int stack_serial_num = _num_threads + STACK_TRACE_ID;
2421 writer()->write_u4(stack_serial_num); // stack trace serial number
2422 writer()->write_u4((u4) _num_threads); // thread serial number
2423 writer()->write_u4(depth); // frame count
2424 for (int j=1; j <= depth; j++) {
2425 writer()->write_id(thread_frame_start + j);
2426 }
2427 }
2428 }
2429}
2430
2431// dump the large objects.
2432void VM_HeapDumper::dump_large_objects(ObjectClosure* cl) {
2433 _large_object_list->drain(cl);
2434}
2435
2436// dump the heap to given path.
2437int HeapDumper::dump(const char* path, outputStream* out, int compression, bool overwrite, uint num_dump_threads) {
2438 assert(path != NULL && strlen(path) > 0, "path missing")do { if (!(path != __null && strlen(path) > 0)) { (
*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 2438, "assert(" "path != __null && strlen(path) > 0"
") failed", "path missing"); ::breakpoint(); } } while (0)
;
2439
2440 // print message in interactive case
2441 if (out != NULL__null) {
2442 out->print_cr("Dumping heap to %s ...", path);
2443 timer()->start();
2444 }
2445 // create JFR event
2446 EventHeapDump event;
2447
2448 AbstractCompressor* compressor = NULL__null;
2449
2450 if (compression > 0) {
2451 compressor = new (std::nothrow) GZipCompressor(compression);
2452
2453 if (compressor == NULL__null) {
2454 set_error("Could not allocate gzip compressor");
2455 return -1;
2456 }
2457 }
2458
2459 DumpWriter writer(new (std::nothrow) FileWriter(path, overwrite), compressor);
2460
2461 if (writer.error() != NULL__null) {
2462 set_error(writer.error());
2463 if (out != NULL__null) {
2464 out->print_cr("Unable to create %s: %s", path,
2465 (error() != NULL__null) ? error() : "reason unknown");
2466 }
2467 return -1;
2468 }
2469
2470 // generate the dump
2471 VM_HeapDumper dumper(&writer, _gc_before_heap_dump, _oome, num_dump_threads);
2472 if (Thread::current()->is_VM_thread()) {
2473 assert(SafepointSynchronize::is_at_safepoint(), "Expected to be called at a safepoint")do { if (!(SafepointSynchronize::is_at_safepoint())) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 2473, "assert(" "SafepointSynchronize::is_at_safepoint()" ") failed"
, "Expected to be called at a safepoint"); ::breakpoint(); } }
while (0)
;
2474 dumper.doit();
2475 } else {
2476 VMThread::execute(&dumper);
2477 }
2478
2479 // record any error that the writer may have encountered
2480 set_error(writer.error());
2481
2482 // emit JFR event
2483 if (error() == NULL__null) {
2484 event.set_destination(path);
2485 event.set_gcBeforeDump(_gc_before_heap_dump);
2486 event.set_size(writer.bytes_written());
2487 event.set_onOutOfMemoryError(_oome);
2488 event.commit();
2489 }
2490
2491 // print message in interactive case
2492 if (out != NULL__null) {
2493 timer()->stop();
2494 if (error() == NULL__null) {
2495 out->print_cr("Heap dump file created [" JULONG_FORMAT"%" "l" "u" " bytes in %3.3f secs]",
2496 writer.bytes_written(), timer()->seconds());
2497 } else {
2498 out->print_cr("Dump file is incomplete: %s", writer.error());
2499 }
2500 }
2501
2502 return (writer.error() == NULL__null) ? 0 : -1;
2503}
2504
2505// stop timer (if still active), and free any error string we might be holding
2506HeapDumper::~HeapDumper() {
2507 if (timer()->is_active()) {
2508 timer()->stop();
2509 }
2510 set_error(NULL__null);
2511}
2512
2513
2514// returns the error string (resource allocated), or NULL
2515char* HeapDumper::error_as_C_string() const {
2516 if (error() != NULL__null) {
2517 char* str = NEW_RESOURCE_ARRAY(char, strlen(error())+1)(char*) resource_allocate_bytes((strlen(error())+1) * sizeof(
char))
;
2518 strcpy(str, error());
2519 return str;
2520 } else {
2521 return NULL__null;
2522 }
2523}
2524
2525// set the error string
2526void HeapDumper::set_error(char const* error) {
2527 if (_error != NULL__null) {
2528 os::free(_error);
2529 }
2530 if (error == NULL__null) {
2531 _error = NULL__null;
2532 } else {
2533 _error = os::strdup(error);
2534 assert(_error != NULL, "allocation failure")do { if (!(_error != __null)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/services/heapDumper.cpp"
, 2534, "assert(" "_error != __null" ") failed", "allocation failure"
); ::breakpoint(); } } while (0)
;
2535 }
2536}
2537
2538// Called by out-of-memory error reporting by a single Java thread
2539// outside of a JVM safepoint
2540void HeapDumper::dump_heap_from_oome() {
2541 HeapDumper::dump_heap(true);
2542}
2543
2544// Called by error reporting by a single Java thread outside of a JVM safepoint,
2545// or by heap dumping by the VM thread during a (GC) safepoint. Thus, these various
2546// callers are strictly serialized and guaranteed not to interfere below. For more
2547// general use, however, this method will need modification to prevent
2548// inteference when updating the static variables base_path and dump_file_seq below.
2549void HeapDumper::dump_heap() {
2550 HeapDumper::dump_heap(false);
2551}
2552
2553void HeapDumper::dump_heap(bool oome) {
2554 static char base_path[JVM_MAXPATHLEN4096 + 1] = {'\0'};
2555 static uint dump_file_seq = 0;
2556 char* my_path;
2557 const int max_digit_chars = 20;
2558
2559 const char* dump_file_name = "java_pid";
2560 const char* dump_file_ext = HeapDumpGzipLevel > 0 ? ".hprof.gz" : ".hprof";
2561
2562 // The dump file defaults to java_pid<pid>.hprof in the current working
2563 // directory. HeapDumpPath=<file> can be used to specify an alternative
2564 // dump file name or a directory where dump file is created.
2565 if (dump_file_seq == 0) { // first time in, we initialize base_path
2566 // Calculate potentially longest base path and check if we have enough
2567 // allocated statically.
2568 const size_t total_length =
2569 (HeapDumpPath == NULL__null ? 0 : strlen(HeapDumpPath)) +
2570 strlen(os::file_separator()) + max_digit_chars +
2571 strlen(dump_file_name) + strlen(dump_file_ext) + 1;
2572 if (total_length > sizeof(base_path)) {
2573 warning("Cannot create heap dump file. HeapDumpPath is too long.");
2574 return;
2575 }
2576
2577 bool use_default_filename = true;
2578 if (HeapDumpPath == NULL__null || HeapDumpPath[0] == '\0') {
2579 // HeapDumpPath=<file> not specified
2580 } else {
2581 strcpy(base_path, HeapDumpPath);
2582 // check if the path is a directory (must exist)
2583 DIR* dir = os::opendir(base_path);
2584 if (dir == NULL__null) {
2585 use_default_filename = false;
2586 } else {
2587 // HeapDumpPath specified a directory. We append a file separator
2588 // (if needed).
2589 os::closedir(dir);
2590 size_t fs_len = strlen(os::file_separator());
2591 if (strlen(base_path) >= fs_len) {
2592 char* end = base_path;
2593 end += (strlen(base_path) - fs_len);
2594 if (strcmp(end, os::file_separator()) != 0) {
2595 strcat(base_path, os::file_separator());
2596 }
2597 }
2598 }
2599 }
2600 // If HeapDumpPath wasn't a file name then we append the default name
2601 if (use_default_filename) {
2602 const size_t dlen = strlen(base_path); // if heap dump dir specified
2603 jio_snprintf(&base_path[dlen], sizeof(base_path)-dlen, "%s%d%s",
2604 dump_file_name, os::current_process_id(), dump_file_ext);
2605 }
2606 const size_t len = strlen(base_path) + 1;
2607 my_path = (char*)os::malloc(len, mtInternal);
2608 if (my_path == NULL__null) {
2609 warning("Cannot create heap dump file. Out of system memory.");
2610 return;
2611 }
2612 strncpy(my_path, base_path, len);
2613 } else {
2614 // Append a sequence number id for dumps following the first
2615 const size_t len = strlen(base_path) + max_digit_chars + 2; // for '.' and \0
2616 my_path = (char*)os::malloc(len, mtInternal);
2617 if (my_path == NULL__null) {
2618 warning("Cannot create heap dump file. Out of system memory.");
2619 return;
2620 }
2621 jio_snprintf(my_path, len, "%s.%d", base_path, dump_file_seq);
2622 }
2623 dump_file_seq++; // increment seq number for next time we dump
2624
2625 HeapDumper dumper(false /* no GC before heap dump */,
2626 oome /* pass along out-of-memory-error flag */);
2627 dumper.dump(my_path, tty, HeapDumpGzipLevel);
2628 os::free(my_path);
2629}