heapDumper.cpp revision 9364:cd86b5699825
1139826Simp/* 253541Sshin * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. 353541Sshin * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 453541Sshin * 553541Sshin * This code is free software; you can redistribute it and/or modify it 653541Sshin * under the terms of the GNU General Public License version 2 only, as 753541Sshin * published by the Free Software Foundation. 853541Sshin * 953541Sshin * This code is distributed in the hope that it will be useful, but WITHOUT 1053541Sshin * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1153541Sshin * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1253541Sshin * version 2 for more details (a copy is included in the LICENSE file that 1353541Sshin * accompanied this code). 1453541Sshin * 1553541Sshin * You should have received a copy of the GNU General Public License version 1653541Sshin * 2 along with this work; if not, write to the Free Software Foundation, 1753541Sshin * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1853541Sshin * 1953541Sshin * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2053541Sshin * or visit www.oracle.com if you need additional information or have any 2153541Sshin * questions. 2253541Sshin * 2353541Sshin */ 2453541Sshin 2553541Sshin#include "precompiled.hpp" 2653541Sshin#include "classfile/symbolTable.hpp" 2753541Sshin#include "classfile/systemDictionary.hpp" 28174510Sobrien#include "classfile/vmSymbols.hpp" 29174510Sobrien#include "gc/shared/gcLocker.inline.hpp" 3053541Sshin#include "gc/shared/genCollectedHeap.hpp" 3153541Sshin#include "gc/shared/vmGCOperations.hpp" 32139826Simp#include "memory/universe.hpp" 3353541Sshin#include "oops/objArrayKlass.hpp" 3453541Sshin#include "oops/objArrayOop.inline.hpp" 3553541Sshin#include "oops/oop.inline.hpp" 3653541Sshin#include "runtime/javaCalls.hpp" 3753541Sshin#include "runtime/jniHandles.hpp" 3853541Sshin#include "runtime/os.hpp" 3953541Sshin#include "runtime/reflectionUtils.hpp" 4053541Sshin#include "runtime/vframe.hpp" 4153541Sshin#include "runtime/vmThread.hpp" 4253541Sshin#include "runtime/vm_operations.hpp" 4353541Sshin#include "services/heapDumper.hpp" 4453541Sshin#include "services/threadService.hpp" 4553541Sshin#include "utilities/macros.hpp" 4653541Sshin#include "utilities/ostream.hpp" 4753541Sshin#if INCLUDE_ALL_GCS 4853541Sshin#include "gc/parallel/parallelScavengeHeap.hpp" 4953541Sshin#endif // INCLUDE_ALL_GCS 5053541Sshin 5153541Sshin/* 5253541Sshin * HPROF binary format - description copied from: 5353541Sshin * src/share/demo/jvmti/hprof/hprof_io.c 5453541Sshin * 5553541Sshin * 5653541Sshin * header "JAVA PROFILE 1.0.1" or "JAVA PROFILE 1.0.2" 5753541Sshin * (0-terminated) 5853541Sshin * 5953541Sshin * u4 size of identifiers. Identifiers are used to represent 6053541Sshin * UTF8 strings, objects, stack traces, etc. They usually 6153541Sshin * have the same size as host pointers. For example, on 6253541Sshin * Solaris and Win32, the size is 4. 63174510Sobrien * u4 high word 64174510Sobrien * u4 low word number of milliseconds since 0:00 GMT, 1/1/70 65174510Sobrien * [record]* a sequence of records. 66272984Srwatson * 67272984Srwatson * 6862587Sitojun * Record format: 6962587Sitojun * 7053541Sshin * u1 a TAG denoting the type of the record 7153541Sshin * u4 number of *microseconds* since the time stamp in the 7295759Stanimura * header. (wraps around in a little more than an hour) 73193066Sjamie * u4 number of bytes *remaining* in the record. Note that 7495759Stanimura * this number excludes the tag and the length field itself. 7595759Stanimura * [u1]* BODY of the record (a sequence of bytes) 7678064Sume * 7753541Sshin * 78196019Srwatson * The following TAGs are supported: 7953541Sshin * 8095759Stanimura * TAG BODY notes 8153541Sshin *---------------------------------------------------------- 8253541Sshin * HPROF_UTF8 a UTF8-encoded name 8395759Stanimura * 8495759Stanimura * id name ID 8595759Stanimura * [u1]* UTF8 characters (no trailing zero) 8653541Sshin * 8753541Sshin * HPROF_LOAD_CLASS a newly loaded class 8853541Sshin * 89257176Sglebius * u4 class serial number (> 0) 9053541Sshin * id class object ID 91186119Sqingli * u4 stack trace serial number 9253541Sshin * id class name ID 9395759Stanimura * 94185571Sbz * HPROF_UNLOAD_CLASS an unloading class 9553541Sshin * 9653541Sshin * u4 class serial_number 9795759Stanimura * 9853541Sshin * HPROF_FRAME a Java stack frame 9962587Sitojun * 10095759Stanimura * id stack frame ID 101122922Sandre * id method name ID 102185571Sbz * id method signature ID 103292015Smelifaro * id source file name ID 10495759Stanimura * u4 class serial number 10595759Stanimura * i4 line number. >0: normal 10695759Stanimura * -1: unknown 10753541Sshin * -2: compiled method 108148385Sume * -3: native method 10953541Sshin * 11053541Sshin * HPROF_TRACE a Java stack trace 111211501Sanchie * 11253541Sshin * u4 stack trace serial number 11362587Sitojun * u4 thread serial number 114185348Szec * u4 number of frames 115253085Sae * [id]* stack frame IDs 116253085Sae * 117207369Sbz * 118253085Sae * HPROF_ALLOC_SITES a set of heap allocation sites, obtained after GC 119253085Sae * 120253085Sae * u2 flags 0x0001: incremental vs. complete 121253085Sae * 0x0002: sorted by allocation vs. live 122195699Srwatson * 0x0004: whether to force a GC 123195699Srwatson * u4 cutoff ratio 124195699Srwatson * u4 total live bytes 125215701Sdim * u4 total live instances 126215701Sdim * u8 total bytes allocated 127195699Srwatson * u8 total instances allocated 12853541Sshin * u4 number of sites that follow 129195727Srwatson * [u1 is_array: 0: normal object 130195727Srwatson * 2: object array 131195727Srwatson * 4: boolean array 132207369Sbz * 5: char array 133207369Sbz * 6: float array 134195727Srwatson * 7: double array 135185088Szec * 8: byte array 136251995Sae * 9: short array 137175162Sobrien * 10: int array 138175162Sobrien * 11: long array 139241916Sdelphij * u4 class serial number (may be zero during startup) 140241916Sdelphij * u4 stack trace serial number 141175162Sobrien * u4 number of bytes alive 142175162Sobrien * u4 number of instances alive 143175162Sobrien * u4 number of bytes allocated 144241916Sdelphij * u4]* number of instance allocated 145241916Sdelphij * 146241916Sdelphij * HPROF_START_THREAD a newly started thread. 147241916Sdelphij * 148175162Sobrien * u4 thread serial number (> 0) 14953541Sshin * id thread object ID 150196039Srwatson * u4 stack trace serial number 151196039Srwatson * id thread name ID 152196039Srwatson * id thread group name ID 153196039Srwatson * id thread group parent name ID 154196039Srwatson * 155196039Srwatson * HPROF_END_THREAD a terminating thread. 156196039Srwatson * 157196039Srwatson * u4 thread serial number 158196039Srwatson * 159196039Srwatson * HPROF_HEAP_SUMMARY heap summary 160196039Srwatson * 161253085Sae * u4 total live bytes 162196039Srwatson * u4 total live instances 163196039Srwatson * u8 total bytes allocated 16462587Sitojun * u8 total instances allocated 165251995Sae * 16662587Sitojun * HPROF_HEAP_DUMP denote a heap dump 16778064Sume * 16862587Sitojun * [heap dump sub-records]* 16962587Sitojun * 17062587Sitojun * There are four kinds of heap dump sub-records: 171251995Sae * 17262587Sitojun * u1 sub-record type 17362587Sitojun * 174251995Sae * HPROF_GC_ROOT_UNKNOWN unknown root 17562587Sitojun * 17662587Sitojun * id object ID 177251995Sae * 17862587Sitojun * HPROF_GC_ROOT_THREAD_OBJ thread object 17962587Sitojun * 180251995Sae * id thread object ID (may be 0 for a 18162587Sitojun * thread newly attached through JNI) 18262587Sitojun * u4 thread sequence number 183251995Sae * u4 stack trace sequence number 18462587Sitojun * 18562587Sitojun * HPROF_GC_ROOT_JNI_GLOBAL JNI global ref root 18662587Sitojun * 18762587Sitojun * id object ID 188251995Sae * id JNI global ref ID 18962587Sitojun * 19062587Sitojun * HPROF_GC_ROOT_JNI_LOCAL JNI local ref 19178064Sume * 19262587Sitojun * id object ID 193251995Sae * u4 thread serial number 19462587Sitojun * u4 frame # in stack trace (-1 for empty) 19562587Sitojun * 196251995Sae * HPROF_GC_ROOT_JAVA_FRAME Java stack frame 19762587Sitojun * 19862587Sitojun * id object ID 19962587Sitojun * u4 thread serial number 20062587Sitojun * u4 frame # in stack trace (-1 for empty) 20178064Sume * 20262587Sitojun * HPROF_GC_ROOT_NATIVE_STACK Native stack 203251995Sae * 20462587Sitojun * id object ID 20562587Sitojun * u4 thread serial number 206251995Sae * 20762587Sitojun * HPROF_GC_ROOT_STICKY_CLASS System class 20862587Sitojun * 209251995Sae * id object ID 21062587Sitojun * 21162587Sitojun * HPROF_GC_ROOT_THREAD_BLOCK Reference from thread block 21262587Sitojun * 21362587Sitojun * id object ID 214251995Sae * u4 thread serial number 21562587Sitojun * 21662587Sitojun * HPROF_GC_ROOT_MONITOR_USED Busy monitor 217251995Sae * 21862587Sitojun * id object ID 21962587Sitojun * 22053541Sshin * HPROF_GC_CLASS_DUMP dump of a class object 221148385Sume * 222148385Sume * id class object ID 223148385Sume * u4 stack trace serial number 224148385Sume * id super class object ID 225171259Sdelphij * id class loader object ID 226171259Sdelphij * id signers object ID 227148385Sume * id protection domain object ID 228148385Sume * id reserved 229148385Sume * id reserved 230148385Sume * 231148385Sume * u4 instance size (in bytes) 232148385Sume * 233148385Sume * u2 size of constant pool 234148385Sume * [u2, constant pool index, 235148385Sume * ty, type 236148385Sume * 2: object 237148385Sume * 4: boolean 238148385Sume * 5: char 239148385Sume * 6: float 240148385Sume * 7: double 241148385Sume * 8: byte 242148385Sume * 9: short 243148385Sume * 10: int 244148385Sume * 11: long 245148385Sume * vl]* and value 246148385Sume * 247148385Sume * u2 number of static fields 248148385Sume * [id, static field name, 249148385Sume * ty, type, 250148385Sume * vl]* and value 251148385Sume * 252148385Sume * u2 number of inst. fields (not inc. super) 253148385Sume * [id, instance field name, 25453541Sshin * ty]* type 25553541Sshin * 25653541Sshin * HPROF_GC_INSTANCE_DUMP dump of a normal object 257171259Sdelphij * 25853541Sshin * id object ID 25953541Sshin * u4 stack trace serial number 26053541Sshin * id class object ID 26162587Sitojun * u4 number of bytes that follow 26253541Sshin * [vl]* instance field values (class, followed 26362587Sitojun * by super, super's super ...) 26453541Sshin * 265190964Srwatson * HPROF_GC_OBJ_ARRAY_DUMP dump of an object array 26653541Sshin * 26762587Sitojun * id array object ID 268251995Sae * u4 stack trace serial number 26962587Sitojun * u4 number of elements 27062587Sitojun * id array class ID 27162587Sitojun * [id]* elements 272190964Srwatson * 27353541Sshin * HPROF_GC_PRIM_ARRAY_DUMP dump of a primitive array 27462587Sitojun * 27562587Sitojun * id array object ID 27653541Sshin * u4 stack trace serial number 27762587Sitojun * u4 number of elements 27862587Sitojun * u1 element type 27962587Sitojun * 4: boolean array 28062587Sitojun * 5: char array 28162587Sitojun * 6: float array 28262587Sitojun * 7: double array 28362587Sitojun * 8: byte array 28462587Sitojun * 9: short array 28562587Sitojun * 10: int array 28653541Sshin * 11: long array 28753541Sshin * [u1]* elements 28853541Sshin * 289121472Sume * HPROF_CPU_SAMPLES a set of sample traces of running threads 290121472Sume * 291121472Sume * u4 total number of samples 292121472Sume * u4 # of traces 293121472Sume * [u4 # of samples 294201688Sbz * u4]* stack trace serial number 295121472Sume * 296121472Sume * HPROF_CONTROL_SETTINGS the settings of on/off switches 297121472Sume * 29853541Sshin * u4 0x00000001: alloc traces on/off 29953541Sshin * 0x00000002: cpu sampling on/off 30053541Sshin * u2 stack trace depth 30153541Sshin * 30253541Sshin * 30353541Sshin * When the header is "JAVA PROFILE 1.0.2" a heap dump can optionally 30453541Sshin * be generated as a sequence of heap dump segments. This sequence is 30553541Sshin * terminated by an end record. The additional tags allowed by format 306121472Sume * "JAVA PROFILE 1.0.2" are: 307121472Sume * 308121472Sume * HPROF_HEAP_DUMP_SEGMENT denote a heap dump segment 309121472Sume * 31053541Sshin * [heap dump sub-records]* 31153541Sshin * The same sub-record types allowed by HPROF_HEAP_DUMP 31253541Sshin * 31353541Sshin * HPROF_HEAP_DUMP_END denotes the end of a heap dump 31453541Sshin * 31562587Sitojun */ 31662587Sitojun 31753541Sshin 31862587Sitojun// HPROF tags 31962587Sitojun 32062587Sitojuntypedef enum { 32153541Sshin // top-level records 32253541Sshin HPROF_UTF8 = 0x01, 32362587Sitojun HPROF_LOAD_CLASS = 0x02, 32462587Sitojun HPROF_UNLOAD_CLASS = 0x03, 32562587Sitojun HPROF_FRAME = 0x04, 32662587Sitojun HPROF_TRACE = 0x05, 32762587Sitojun HPROF_ALLOC_SITES = 0x06, 32862587Sitojun HPROF_HEAP_SUMMARY = 0x07, 32962587Sitojun HPROF_START_THREAD = 0x0A, 330190964Srwatson HPROF_END_THREAD = 0x0B, 33162587Sitojun HPROF_HEAP_DUMP = 0x0C, 33262587Sitojun HPROF_CPU_SAMPLES = 0x0D, 33362587Sitojun HPROF_CONTROL_SETTINGS = 0x0E, 33462587Sitojun 33562587Sitojun // 1.0.2 record types 33653541Sshin HPROF_HEAP_DUMP_SEGMENT = 0x1C, 33762587Sitojun HPROF_HEAP_DUMP_END = 0x2C, 33862587Sitojun 33962587Sitojun // field types 34053541Sshin HPROF_ARRAY_OBJECT = 0x01, 341190964Srwatson HPROF_NORMAL_OBJECT = 0x02, 34262587Sitojun HPROF_BOOLEAN = 0x04, 34362587Sitojun HPROF_CHAR = 0x05, 34462587Sitojun HPROF_FLOAT = 0x06, 34553541Sshin HPROF_DOUBLE = 0x07, 34662587Sitojun HPROF_BYTE = 0x08, 34762587Sitojun HPROF_SHORT = 0x09, 34853541Sshin HPROF_INT = 0x0A, 34953541Sshin HPROF_LONG = 0x0B, 35053541Sshin 35153541Sshin // data-dump sub-records 35253541Sshin HPROF_GC_ROOT_UNKNOWN = 0xFF, 35353541Sshin HPROF_GC_ROOT_JNI_GLOBAL = 0x01, 354190964Srwatson HPROF_GC_ROOT_JNI_LOCAL = 0x02, 35553541Sshin HPROF_GC_ROOT_JAVA_FRAME = 0x03, 35653541Sshin HPROF_GC_ROOT_NATIVE_STACK = 0x04, 35753541Sshin HPROF_GC_ROOT_STICKY_CLASS = 0x05, 35853541Sshin HPROF_GC_ROOT_THREAD_BLOCK = 0x06, 35953541Sshin HPROF_GC_ROOT_MONITOR_USED = 0x07, 36053541Sshin HPROF_GC_ROOT_THREAD_OBJ = 0x08, 36153541Sshin HPROF_GC_CLASS_DUMP = 0x20, 36253541Sshin HPROF_GC_INSTANCE_DUMP = 0x21, 36353541Sshin HPROF_GC_OBJ_ARRAY_DUMP = 0x22, 36453541Sshin HPROF_GC_PRIM_ARRAY_DUMP = 0x23 36562587Sitojun} hprofTag; 366243882Sglebius 36753541Sshin// Default stack trace ID (used for dummy HPROF_TRACE record) 36878064Sumeenum { 36953541Sshin STACK_TRACE_ID = 1, 37053541Sshin INITIAL_CLASS_COUNT = 200 37153541Sshin}; 37253541Sshin 37353541Sshin// Supports I/O operations on a dump file 37453541Sshin 37553541Sshinclass DumpWriter : public StackObj { 376121315Sume private: 377121315Sume enum { 37853541Sshin io_buffer_size = 8*M 37953541Sshin }; 38053541Sshin 38153541Sshin int _fd; // file descriptor (-1 if dump file not open) 38253541Sshin jlong _bytes_written; // number of byte written to dump file 38353541Sshin 38478064Sume char* _buffer; // internal buffer 38578064Sume int _size; 386148987Sume int _pos; 38778064Sume 38878064Sume char* _error; // error message when I/O fails 38978064Sume 39078064Sume void set_file_descriptor(int fd) { _fd = fd; } 39178064Sume int file_descriptor() const { return _fd; } 39278064Sume 393190964Srwatson char* buffer() const { return _buffer; } 39495023Ssuz int buffer_size() const { return _size; } 39562587Sitojun int position() const { return _pos; } 39662587Sitojun void set_position(int pos) { _pos = pos; } 39762587Sitojun 39862587Sitojun void set_error(const char* error) { _error = (char*)os::strdup(error); } 39962587Sitojun 400148987Sume // all I/O go through this function 40162587Sitojun void write_internal(void* s, int len); 40262587Sitojun 40353541Sshin public: 40453541Sshin DumpWriter(const char* path); 40553541Sshin ~DumpWriter(); 40653541Sshin 40753541Sshin void close(); 40853541Sshin bool is_open() const { return file_descriptor() >= 0; } 409171259Sdelphij void flush(); 41053541Sshin 41153541Sshin // total number of bytes written to the disk 412192923Sbms jlong bytes_written() const { return _bytes_written; } 41353541Sshin 41453541Sshin // adjust the number of bytes written to disk (used to keep the count 41553541Sshin // of the number of bytes written in case of rewrites) 41653541Sshin void adjust_bytes_written(jlong n) { _bytes_written += n; } 41753541Sshin 418165118Sbz // number of (buffered) bytes as yet unwritten to the dump file 419211501Sanchie jlong bytes_unwritten() const { return (jlong)position(); } 42053541Sshin 421192923Sbms char* error() const { return _error; } 422192923Sbms 42362587Sitojun jlong current_offset(); 42453541Sshin void seek_to_offset(jlong pos); 42595023Ssuz 42662587Sitojun // writer functions 42753541Sshin void write_raw(void* s, int len); 42853541Sshin void write_u1(u1 x) { write_raw((void*)&x, 1); } 42953541Sshin void write_u2(u2 x); 43053541Sshin void write_u4(u4 x); 43153541Sshin void write_u8(u8 x); 43253541Sshin void write_objectID(oop o); 43353541Sshin void write_symbolID(Symbol* o); 434211501Sanchie void write_classID(Klass* k); 43553541Sshin void write_id(u4 x); 436190964Srwatson}; 43753541Sshin 43853541SshinDumpWriter::DumpWriter(const char* path) { 43953541Sshin // try to allocate an I/O buffer of io_buffer_size. If there isn't 44053541Sshin // sufficient memory then reduce size until we can allocate something. 441191672Sbms _size = io_buffer_size; 442191672Sbms do { 443191672Sbms _buffer = (char*)os::malloc(_size, mtInternal); 444191672Sbms if (_buffer == NULL) { 445192923Sbms _size = _size >> 1; 446191672Sbms } 447191672Sbms } while (_buffer == NULL && _size > 0); 448191672Sbms assert((_size > 0 && _buffer != NULL) || (_size == 0 && _buffer == NULL), "sanity check"); 449191672Sbms _pos = 0; 450191672Sbms _error = NULL; 451191672Sbms _bytes_written = 0L; 452191672Sbms _fd = os::create_binary_file(path, false); // don't replace existing file 453191672Sbms 454191672Sbms // if the open failed we record the error 455191672Sbms if (_fd < 0) { 45653541Sshin _error = (char*)os::strdup(strerror(errno)); 45753541Sshin } 45862587Sitojun} 45953541Sshin 46062587SitojunDumpWriter::~DumpWriter() { 46162587Sitojun // flush and close dump file 46262587Sitojun if (is_open()) { 463190964Srwatson close(); 46462587Sitojun } 46562587Sitojun if (_buffer != NULL) os::free(_buffer); 46662587Sitojun if (_error != NULL) os::free(_error); 46753541Sshin} 46853541Sshin 46953541Sshin// closes dump file (if open) 47078064Sumevoid DumpWriter::close() { 47153541Sshin // flush and close dump file 472165118Sbz if (is_open()) { 473165118Sbz flush(); 474190964Srwatson ::close(file_descriptor()); 47553541Sshin set_file_descriptor(-1); 47653541Sshin } 47753541Sshin} 478190964Srwatson 479192923Sbms// write directly to the file 48053541Sshinvoid DumpWriter::write_internal(void* s, int len) { 481192923Sbms if (is_open()) { 48253541Sshin int n = ::write(file_descriptor(), s, len); 48353541Sshin if (n > 0) { 48453541Sshin _bytes_written += n; 485192923Sbms } 48653541Sshin if (n != len) { 48753541Sshin if (n < 0) { 48853541Sshin set_error(strerror(errno)); 48953541Sshin } else { 49053541Sshin set_error("file size limit"); 491192923Sbms } 49262587Sitojun ::close(file_descriptor()); 49362587Sitojun set_file_descriptor(-1); 49453541Sshin } 49562587Sitojun } 49653541Sshin} 49762587Sitojun 49862587Sitojun// write raw bytes 49962587Sitojunvoid DumpWriter::write_raw(void* s, int len) { 50062587Sitojun if (is_open()) { 50153541Sshin // flush buffer to make toom 50253541Sshin if ((position()+ len) >= buffer_size()) { 50353541Sshin flush(); 50453541Sshin } 50553541Sshin 50653541Sshin // buffer not available or too big to buffer it 50753541Sshin if ((buffer() == NULL) || (len >= buffer_size())) { 50853541Sshin write_internal(s, len); 50953541Sshin } else { 51053541Sshin // Should optimize this for u1/u2/u4/u8 sizes. 511192923Sbms memcpy(buffer() + position(), s, len); 51253541Sshin set_position(position() + len); 513126194Sume } 514126194Sume } 51553541Sshin} 51653541Sshin 51762587Sitojun// flush any buffered bytes to the file 51862587Sitojunvoid DumpWriter::flush() { 51962587Sitojun if (is_open() && position() > 0) { 52062587Sitojun write_internal(buffer(), position()); 52153541Sshin set_position(0); 52253541Sshin } 52353541Sshin} 52453541Sshin 525192923Sbms 52653541Sshinjlong DumpWriter::current_offset() { 52753541Sshin if (is_open()) { 528151465Ssuz // the offset is the file offset plus whatever we have buffered 529151465Ssuz jlong offset = os::current_file_offset(file_descriptor()); 53053541Sshin assert(offset >= 0, "lseek failed"); 531151465Ssuz return offset + (jlong)position(); 53253541Sshin } else { 53353541Sshin return (jlong)-1; 53453541Sshin } 53553541Sshin} 53653541Sshin 53753541Sshinvoid DumpWriter::seek_to_offset(jlong off) { 53853541Sshin assert(off >= 0, "bad offset"); 53953541Sshin 540192923Sbms // need to flush before seeking 54153541Sshin flush(); 54253541Sshin 54353541Sshin // may be closed due to I/O error 54453541Sshin if (is_open()) { 54553541Sshin jlong n = os::seek_to_file_offset(file_descriptor(), off); 54653541Sshin assert(n >= 0, "lseek failed"); 54753541Sshin } 54853541Sshin} 54953541Sshin 55053541Sshinvoid DumpWriter::write_u2(u2 x) { 55153541Sshin u2 v; 55253541Sshin Bytes::put_Java_u2((address)&v, x); 55353541Sshin write_raw((void*)&v, 2); 55453541Sshin} 55553541Sshin 556192923Sbmsvoid DumpWriter::write_u4(u4 x) { 55753541Sshin u4 v; 55853541Sshin Bytes::put_Java_u4((address)&v, x); 55953541Sshin write_raw((void*)&v, 4); 56053541Sshin} 56153541Sshin 56253541Sshinvoid DumpWriter::write_u8(u8 x) { 563272984Srwatson u8 v; 56462587Sitojun Bytes::put_Java_u8((address)&v, x); 56553541Sshin write_raw((void*)&v, 8); 566108741Ssam} 56753541Sshin 568248328Sglebiusvoid DumpWriter::write_objectID(oop o) { 569248321Sglebius address a = (address)o; 57053541Sshin#ifdef _LP64 57153541Sshin write_u8((u8)a); 57253541Sshin#else 57353541Sshin write_u4((u4)a); 57453541Sshin#endif 575248328Sglebius} 576248328Sglebius 577248328Sglebiusvoid DumpWriter::write_symbolID(Symbol* s) { 57853541Sshin address a = (address)((uintptr_t)s); 57953541Sshin#ifdef _LP64 58053541Sshin write_u8((u8)a); 58153541Sshin#else 58253541Sshin write_u4((u4)a); 58353541Sshin#endif 58453541Sshin} 58562587Sitojun 586108741Ssamvoid DumpWriter::write_id(u4 x) { 587108741Ssam#ifdef _LP64 58853541Sshin write_u8((u8) x); 589120891Sume#else 59062587Sitojun write_u4(x); 59153541Sshin#endif 59262587Sitojun} 593108741Ssam 594108741Ssam// We use java mirror as the class ID 59562587Sitojunvoid DumpWriter::write_classID(Klass* k) { 59653541Sshin write_objectID(k->java_mirror()); 59753541Sshin} 598166046Sume 599166046Sume 60053541Sshin 60153541Sshin// Support class with a collection of functions used when dumping the heap 60253541Sshin 60353541Sshinclass DumperSupport : AllStatic { 60453541Sshin public: 605190964Srwatson 606190964Srwatson // write a header of the given type 60753541Sshin static void write_header(DumpWriter* writer, hprofTag tag, u4 len); 60853541Sshin 60953541Sshin // returns hprof tag for the given type signature 61053541Sshin static hprofTag sig2tag(Symbol* sig); 61153541Sshin // returns hprof tag for the given basic type 612192923Sbms static hprofTag type2tag(BasicType type); 61353541Sshin 61453541Sshin // returns the size of the instance of the given class 61553541Sshin static u4 instance_size(Klass* k); 61653541Sshin 61796116Sume // dump a jfloat 61896116Sume static void dump_float(DumpWriter* writer, jfloat f); 619191672Sbms // dump a jdouble 620191672Sbms static void dump_double(DumpWriter* writer, jdouble d); 621191672Sbms // dumps the raw value of the given field 622192923Sbms static void dump_field_value(DumpWriter* writer, char type, address addr); 623192923Sbms // dumps static fields of the given class 624192923Sbms static void dump_static_fields(DumpWriter* writer, Klass* k); 625192923Sbms // dump the raw values of the instance fields of the given object 626192923Sbms static void dump_instance_fields(DumpWriter* writer, oop o); 627191672Sbms // dumps the definition of the instance fields for a given class 628191672Sbms static void dump_instance_field_descriptors(DumpWriter* writer, Klass* k); 629191672Sbms // creates HPROF_GC_INSTANCE_DUMP record for the given object 630192923Sbms static void dump_instance(DumpWriter* writer, oop o); 63162587Sitojun // creates HPROF_GC_CLASS_DUMP record for the given class and each of its 632191672Sbms // array classes 633191672Sbms static void dump_class_and_array_classes(DumpWriter* writer, Klass* k); 63453541Sshin // creates HPROF_GC_CLASS_DUMP record for a given primitive array 63553541Sshin // class (and each multi-dimensional array class too) 63653541Sshin static void dump_basic_type_array_class(DumpWriter* writer, Klass* k); 63753541Sshin 63853541Sshin // creates HPROF_GC_OBJ_ARRAY_DUMP record for the given object array 63953541Sshin static void dump_object_array(DumpWriter* writer, objArrayOop array); 64053541Sshin // creates HPROF_GC_PRIM_ARRAY_DUMP record for the given type array 641181803Sbz static void dump_prim_array(DumpWriter* writer, typeArrayOop array); 64262587Sitojun // create HPROF_FRAME record for the given method and bci 64362587Sitojun static void dump_stack_frame(DumpWriter* writer, int frame_serial_num, int class_serial_num, Method* m, int bci); 64453541Sshin}; 64553541Sshin 64662587Sitojun// write a header of the given type 64753541Sshinvoid DumperSupport:: write_header(DumpWriter* writer, hprofTag tag, u4 len) { 64853541Sshin writer->write_u1((u1)tag); 64953541Sshin writer->write_u4(0); // current ticks 65053541Sshin writer->write_u4(len); 65153541Sshin} 65262587Sitojun 65353541Sshin// returns hprof tag for the given type signature 654120891SumehprofTag DumperSupport::sig2tag(Symbol* sig) { 65562587Sitojun switch (sig->byte_at(0)) { 65662587Sitojun case JVM_SIGNATURE_CLASS : return HPROF_NORMAL_OBJECT; 65762587Sitojun case JVM_SIGNATURE_ARRAY : return HPROF_NORMAL_OBJECT; 65862587Sitojun case JVM_SIGNATURE_BYTE : return HPROF_BYTE; 65962587Sitojun case JVM_SIGNATURE_CHAR : return HPROF_CHAR; 66053541Sshin case JVM_SIGNATURE_FLOAT : return HPROF_FLOAT; 66153541Sshin case JVM_SIGNATURE_DOUBLE : return HPROF_DOUBLE; 662193066Sjamie case JVM_SIGNATURE_INT : return HPROF_INT; 66353541Sshin case JVM_SIGNATURE_LONG : return HPROF_LONG; 664248328Sglebius case JVM_SIGNATURE_SHORT : return HPROF_SHORT; 66553541Sshin case JVM_SIGNATURE_BOOLEAN : return HPROF_BOOLEAN; 666169664Sjinmei default : ShouldNotReachHere(); /* to shut up compiler */ return HPROF_BYTE; 667169664Sjinmei } 668169664Sjinmei} 669169664Sjinmei 670299829SmarkjhprofTag DumperSupport::type2tag(BasicType type) { 671299829Smarkj switch (type) { 672299829Smarkj case T_BYTE : return HPROF_BYTE; 67378064Sume case T_CHAR : return HPROF_CHAR; 67478064Sume case T_FLOAT : return HPROF_FLOAT; 67562587Sitojun case T_DOUBLE : return HPROF_DOUBLE; 67662587Sitojun case T_INT : return HPROF_INT; 677248328Sglebius case T_LONG : return HPROF_LONG; 678248328Sglebius case T_SHORT : return HPROF_SHORT; 679248328Sglebius case T_BOOLEAN : return HPROF_BOOLEAN; 680248328Sglebius default : ShouldNotReachHere(); /* to shut up compiler */ return HPROF_BYTE; 68162587Sitojun } 68262587Sitojun} 68362587Sitojun 684248328Sglebius// dump a jfloat 685108466Ssamvoid DumperSupport::dump_float(DumpWriter* writer, jfloat f) { 686108466Ssam if (g_isnan(f)) { 687108466Ssam writer->write_u4(0x7fc00000); // collapsing NaNs 688108466Ssam } else { 689108466Ssam union { 690108466Ssam int i; 691108466Ssam float f; 692108466Ssam } u; 693108466Ssam u.f = (float)f; 694108466Ssam writer->write_u4((u4)u.i); 695248328Sglebius } 696248328Sglebius} 697193066Sjamie 698193066Sjamie// dump a jdouble 699194118Sjamievoid DumperSupport::dump_double(DumpWriter* writer, jdouble d) { 700193066Sjamie union { 701193066Sjamie jlong l; 70253541Sshin double d; 70353541Sshin } u; 70453541Sshin if (g_isnan(d)) { // collapsing NaNs 70553541Sshin u.l = (jlong)(0x7ff80000); 70653541Sshin u.l = (u.l << 32); 70753541Sshin } else { 70853541Sshin u.d = (double)d; 70953541Sshin } 71053541Sshin writer->write_u8((u8)u.l); 711194118Sjamie} 712194118Sjamie 713193066Sjamie// dumps the raw value of the given field 71453541Sshinvoid DumperSupport::dump_field_value(DumpWriter* writer, char type, address addr) { 71553541Sshin switch (type) { 71662587Sitojun case JVM_SIGNATURE_CLASS : 71753541Sshin case JVM_SIGNATURE_ARRAY : { 71853541Sshin oop o; 71953541Sshin if (UseCompressedOops) { 72053541Sshin o = oopDesc::load_decode_heap_oop((narrowOop*)addr); 721190964Srwatson } else { 722190964Srwatson o = oopDesc::load_decode_heap_oop((oop*)addr); 72353541Sshin } 72453541Sshin 72553541Sshin // reflection and Unsafe classes may have a reference to a 72653541Sshin // Klass* so filter it out. 72753541Sshin assert(o->is_oop_or_null(), "Expected an oop or NULL at " PTR_FORMAT, p2i(o)); 72853541Sshin writer->write_objectID(o); 72953541Sshin break; 73053541Sshin } 73153541Sshin case JVM_SIGNATURE_BYTE : { 73253541Sshin jbyte* b = (jbyte*)addr; 73353541Sshin writer->write_u1((u1)*b); 734192923Sbms break; 73553541Sshin } 73653541Sshin case JVM_SIGNATURE_CHAR : { 73753541Sshin jchar* c = (jchar*)addr; 73853541Sshin writer->write_u2((u2)*c); 739243882Sglebius break; 74062587Sitojun } 741211501Sanchie case JVM_SIGNATURE_SHORT : { 742211501Sanchie jshort* s = (jshort*)addr; 743211501Sanchie writer->write_u2((u2)*s); 744211501Sanchie break; 745211501Sanchie } 746211501Sanchie case JVM_SIGNATURE_FLOAT : { 747211501Sanchie jfloat* f = (jfloat*)addr; 748211501Sanchie dump_float(writer, *f); 749211501Sanchie break; 750211501Sanchie } 751211501Sanchie case JVM_SIGNATURE_DOUBLE : { 752211501Sanchie jdouble* f = (jdouble*)addr; 753211501Sanchie dump_double(writer, *f); 75462587Sitojun break; 75562587Sitojun } 75662587Sitojun case JVM_SIGNATURE_INT : { 757211501Sanchie jint* i = (jint*)addr; 758211520Sanchie writer->write_u4((u4)*i); 759211501Sanchie break; 760211501Sanchie } 761211501Sanchie case JVM_SIGNATURE_LONG : { 762211520Sanchie jlong* l = (jlong*)addr; 763211520Sanchie writer->write_u8((u8)*l); 764211501Sanchie break; 765211501Sanchie } 766211501Sanchie case JVM_SIGNATURE_BOOLEAN : { 767211501Sanchie jboolean* b = (jboolean*)addr; 76853541Sshin writer->write_u1((u1)*b); 76953541Sshin break; 77053541Sshin } 77153541Sshin default : ShouldNotReachHere(); 772192923Sbms } 77353541Sshin} 77453541Sshin 77553541Sshin// returns the size of the instance of the given class 77653541Sshinu4 DumperSupport::instance_size(Klass* k) { 777243882Sglebius HandleMark hm; 778211501Sanchie instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), k); 779211501Sanchie 780211501Sanchie int size = 0; 781211501Sanchie 782211501Sanchie for (FieldStream fld(ikh, false, false); !fld.eos(); fld.next()) { 783211501Sanchie if (!fld.access_flags().is_static()) { 784211501Sanchie Symbol* sig = fld.signature(); 785211501Sanchie switch (sig->byte_at(0)) { 786211501Sanchie case JVM_SIGNATURE_CLASS : 787211501Sanchie case JVM_SIGNATURE_ARRAY : size += oopSize; break; 78862587Sitojun 78962587Sitojun case JVM_SIGNATURE_BYTE : 79062587Sitojun case JVM_SIGNATURE_BOOLEAN : size += 1; break; 791211501Sanchie 792211501Sanchie case JVM_SIGNATURE_CHAR : 793211501Sanchie case JVM_SIGNATURE_SHORT : size += 2; break; 794211501Sanchie 795211520Sanchie case JVM_SIGNATURE_INT : 796211501Sanchie case JVM_SIGNATURE_FLOAT : size += 4; break; 797211501Sanchie 798211501Sanchie case JVM_SIGNATURE_LONG : 79953541Sshin case JVM_SIGNATURE_DOUBLE : size += 8; break; 80053541Sshin 80153541Sshin default : ShouldNotReachHere(); 80253541Sshin } 803192923Sbms } 80453541Sshin } 80553541Sshin return (u4)size; 80653541Sshin} 80753541Sshin 808243882Sglebius// dumps static fields of the given class 809211501Sanchievoid DumperSupport::dump_static_fields(DumpWriter* writer, Klass* k) { 810211501Sanchie HandleMark hm; 811211501Sanchie instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), k); 812211501Sanchie 813211501Sanchie // pass 1 - count the static fields 814211501Sanchie u2 field_count = 0; 815211501Sanchie for (FieldStream fldc(ikh, true, true); !fldc.eos(); fldc.next()) { 816211501Sanchie if (fldc.access_flags().is_static()) field_count++; 81762587Sitojun } 81862587Sitojun 81962587Sitojun writer->write_u2(field_count); 820211501Sanchie 821211501Sanchie // pass 2 - dump the field descriptors and raw values 822211501Sanchie for (FieldStream fld(ikh, true, true); !fld.eos(); fld.next()) { 823211501Sanchie if (fld.access_flags().is_static()) { 824211520Sanchie Symbol* sig = fld.signature(); 825211501Sanchie 826211501Sanchie writer->write_symbolID(fld.name()); // name 827211501Sanchie writer->write_u1(sig2tag(sig)); // type 82853541Sshin 82953541Sshin // value 83053541Sshin int offset = fld.offset(); 83153541Sshin address addr = (address)ikh->java_mirror() + offset; 832192923Sbms 83353541Sshin dump_field_value(writer, sig->byte_at(0), addr); 83453541Sshin } 83553541Sshin } 83653541Sshin} 837243882Sglebius 838211501Sanchie// dump the raw values of the instance fields of the given object 839211501Sanchievoid DumperSupport::dump_instance_fields(DumpWriter* writer, oop o) { 840211501Sanchie HandleMark hm; 841211501Sanchie instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), o->klass()); 842211501Sanchie 843211501Sanchie for (FieldStream fld(ikh, false, false); !fld.eos(); fld.next()) { 844211501Sanchie if (!fld.access_flags().is_static()) { 845211501Sanchie Symbol* sig = fld.signature(); 846211501Sanchie address addr = (address)o + fld.offset(); 847211501Sanchie 84862587Sitojun dump_field_value(writer, sig->byte_at(0), addr); 84962587Sitojun } 85062587Sitojun } 851211501Sanchie} 852211501Sanchie 853211501Sanchie// dumps the definition of the instance fields for a given class 854211501Sanchievoid DumperSupport::dump_instance_field_descriptors(DumpWriter* writer, Klass* k) { 855211520Sanchie HandleMark hm; 856211501Sanchie instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), k); 857211501Sanchie 858211501Sanchie // pass 1 - count the instance fields 85953541Sshin u2 field_count = 0; 86053541Sshin for (FieldStream fldc(ikh, true, true); !fldc.eos(); fldc.next()) { 86153541Sshin if (!fldc.access_flags().is_static()) field_count++; 86253541Sshin } 863192923Sbms 86453541Sshin writer->write_u2(field_count); 86553541Sshin 86653541Sshin // pass 2 - dump the field descriptors 86753541Sshin for (FieldStream fld(ikh, true, true); !fld.eos(); fld.next()) { 868243882Sglebius if (!fld.access_flags().is_static()) { 869211501Sanchie Symbol* sig = fld.signature(); 870211501Sanchie 871211501Sanchie writer->write_symbolID(fld.name()); // name 872211501Sanchie writer->write_u1(sig2tag(sig)); // type 873211501Sanchie } 874211501Sanchie } 875211501Sanchie} 876211501Sanchie 87762587Sitojun// creates HPROF_GC_INSTANCE_DUMP record for the given object 87862587Sitojunvoid DumperSupport::dump_instance(DumpWriter* writer, oop o) { 87962587Sitojun Klass* k = o->klass(); 880211501Sanchie 881211501Sanchie writer->write_u1(HPROF_GC_INSTANCE_DUMP); 882211501Sanchie writer->write_objectID(o); 883211501Sanchie writer->write_u4(STACK_TRACE_ID); 884211520Sanchie 885211501Sanchie // class ID 886211501Sanchie writer->write_classID(k); 887211501Sanchie 88853541Sshin // number of bytes that follow 88953541Sshin writer->write_u4(instance_size(k) ); 89053541Sshin 89153541Sshin // field values 89253541Sshin dump_instance_fields(writer, o); 89353541Sshin} 89453541Sshin 89553541Sshin// creates HPROF_GC_CLASS_DUMP record for the given class and each of 89653541Sshin// its array classes 89753541Sshinvoid DumperSupport::dump_class_and_array_classes(DumpWriter* writer, Klass* k) { 89853541Sshin InstanceKlass* ik = InstanceKlass::cast(k); 89953541Sshin 90078064Sume // We can safepoint and do a heap dump at a point where we have a Klass, 90178064Sume // but no java mirror class has been setup for it. So we need to check 902165118Sbz // that the class is at least loaded, to avoid crash from a null mirror. 903165118Sbz if (!ik->is_loaded()) { 904192923Sbms return; 90553541Sshin } 90653541Sshin 90753541Sshin writer->write_u1(HPROF_GC_CLASS_DUMP); 90853541Sshin 90953541Sshin // class ID 91053541Sshin writer->write_classID(ik); 91153541Sshin writer->write_u4(STACK_TRACE_ID); 91253541Sshin 91353541Sshin // super class ID 914198076Sbz Klass* java_super = ik->java_super(); 91578064Sume if (java_super == NULL) { 916120856Sume writer->write_objectID(oop(NULL)); 91753541Sshin } else { 91878064Sume writer->write_classID(java_super); 91978064Sume } 92078064Sume 921190964Srwatson writer->write_objectID(ik->class_loader()); 92278064Sume writer->write_objectID(ik->signers()); 92378064Sume writer->write_objectID(ik->protection_domain()); 92478064Sume 925190964Srwatson // reserved 92678064Sume writer->write_objectID(oop(NULL)); 92778064Sume writer->write_objectID(oop(NULL)); 92878064Sume 92978064Sume // instance size 93078064Sume writer->write_u4(DumperSupport::instance_size(k)); 93178064Sume 93278064Sume // size of constant pool - ignored by HAT 1.1 93378064Sume writer->write_u2(0); 93478064Sume 93578064Sume // number of static fields 93678064Sume dump_static_fields(writer, k); 93778064Sume 93878064Sume // description of instance fields 93978064Sume dump_instance_field_descriptors(writer, k); 940171259Sdelphij 94178064Sume // array classes 942142681Sume k = k->array_klass_or_null(); 94378064Sume while (k != NULL) { 94478064Sume Klass* klass = k; 94578064Sume assert(klass->is_objArray_klass(), "not an ObjArrayKlass"); 94678064Sume 94778064Sume writer->write_u1(HPROF_GC_CLASS_DUMP); 94878064Sume writer->write_classID(klass); 949190964Srwatson writer->write_u4(STACK_TRACE_ID); 95078064Sume 95178064Sume // super class of array classes is java.lang.Object 95262587Sitojun java_super = klass->java_super(); 95378064Sume assert(java_super != NULL, "checking"); 954120891Sume writer->write_classID(java_super); 95578064Sume 95662587Sitojun writer->write_objectID(ik->class_loader()); 95778064Sume writer->write_objectID(ik->signers()); 958120891Sume writer->write_objectID(ik->protection_domain()); 95978064Sume 960190964Srwatson writer->write_objectID(oop(NULL)); // reserved 961120856Sume writer->write_objectID(oop(NULL)); 96278064Sume writer->write_u4(0); // instance size 96362587Sitojun writer->write_u2(0); // constant pool 96478064Sume writer->write_u2(0); // static fields 96553541Sshin writer->write_u2(0); // instance fields 96678064Sume 96778064Sume // get the array class for the next rank 968175162Sobrien k = klass->array_klass_or_null(); 96953541Sshin } 97053541Sshin} 971120891Sume 97253541Sshin// creates HPROF_GC_CLASS_DUMP record for a given primitive array 97362587Sitojun// class (and each multi-dimensional array class too) 97462587Sitojunvoid DumperSupport::dump_basic_type_array_class(DumpWriter* writer, Klass* k) { 97562587Sitojun // array classes 97662587Sitojun while (k != NULL) { 97762587Sitojun Klass* klass = k; 97862587Sitojun 97953541Sshin writer->write_u1(HPROF_GC_CLASS_DUMP); 98095023Ssuz writer->write_classID(klass); 98153541Sshin writer->write_u4(STACK_TRACE_ID); 98253541Sshin 98378064Sume // super class of array classes is java.lang.Object 98453541Sshin Klass* java_super = klass->java_super(); 98553541Sshin assert(java_super != NULL, "checking"); 98653541Sshin writer->write_classID(java_super); 98762587Sitojun 988120891Sume writer->write_objectID(oop(NULL)); // loader 989120891Sume writer->write_objectID(oop(NULL)); // signers 990120892Sume writer->write_objectID(oop(NULL)); // protection domain 99162587Sitojun 99262587Sitojun writer->write_objectID(oop(NULL)); // reserved 993120891Sume writer->write_objectID(oop(NULL)); 99462587Sitojun writer->write_u4(0); // instance size 995190964Srwatson writer->write_u2(0); // constant pool 996120856Sume writer->write_u2(0); // static fields 99762587Sitojun writer->write_u2(0); // instance fields 99862587Sitojun 999120891Sume // get the array class for the next rank 100053541Sshin k = klass->array_klass_or_null(); 100153541Sshin } 100253541Sshin} 100353541Sshin 100453541Sshin// creates HPROF_GC_OBJ_ARRAY_DUMP record for the given object array 100553541Sshinvoid DumperSupport::dump_object_array(DumpWriter* writer, objArrayOop array) { 100662587Sitojun 100762587Sitojun writer->write_u1(HPROF_GC_OBJ_ARRAY_DUMP); 100862587Sitojun writer->write_objectID(array); 100962587Sitojun writer->write_u4(STACK_TRACE_ID); 101062587Sitojun writer->write_u4((u4)array->length()); 101162587Sitojun 101262587Sitojun // array class ID 101362587Sitojun writer->write_classID(array->klass()); 101462587Sitojun 101562587Sitojun // [id]* elements 1016120891Sume for (int index=0; index<array->length(); index++) { 1017120891Sume oop o = array->obj_at(index); 1018120891Sume writer->write_objectID(o); 101962587Sitojun } 102062587Sitojun} 1021120891Sume 102262587Sitojun#define WRITE_ARRAY(Array, Type, Size) \ 1023190964Srwatson for (int i=0; i<Array->length(); i++) { writer->write_##Size((Size)array->Type##_at(i)); } 1024120856Sume 102562587Sitojun 102662587Sitojun// creates HPROF_GC_PRIM_ARRAY_DUMP record for the given type array 102762587Sitojunvoid DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) { 102862587Sitojun BasicType type = TypeArrayKlass::cast(array->klass())->element_type(); 102962587Sitojun 103062587Sitojun writer->write_u1(HPROF_GC_PRIM_ARRAY_DUMP); 103162587Sitojun writer->write_objectID(array); 103262587Sitojun writer->write_u4(STACK_TRACE_ID); 103362587Sitojun writer->write_u4((u4)array->length()); 103462587Sitojun writer->write_u1(type2tag(type)); 103562587Sitojun 103662587Sitojun // nothing to copy 103762587Sitojun if (array->length() == 0) { 103862587Sitojun return; 103962587Sitojun } 104062587Sitojun 1041120891Sume // If the byte ordering is big endian then we can copy most types directly 1042120891Sume int length_in_bytes = array->length() * type2aelembytes(type); 1043120891Sume assert(length_in_bytes > 0, "nothing to copy"); 104462587Sitojun 104562587Sitojun switch (type) { 1046120891Sume case T_INT : { 1047120891Sume if (Bytes::is_Java_byte_ordering_different()) { 104862587Sitojun WRITE_ARRAY(array, int, u4); 1049190964Srwatson } else { 1050120856Sume writer->write_raw((void*)(array->int_at_addr(0)), length_in_bytes); 105162587Sitojun } 105262587Sitojun break; 105362587Sitojun } 105462587Sitojun case T_BYTE : { 105562587Sitojun writer->write_raw((void*)(array->byte_at_addr(0)), length_in_bytes); 105662587Sitojun break; 105762587Sitojun } 105862587Sitojun case T_CHAR : { 105962587Sitojun if (Bytes::is_Java_byte_ordering_different()) { 106062587Sitojun WRITE_ARRAY(array, char, u2); 106162587Sitojun } else { 106262587Sitojun writer->write_raw((void*)(array->char_at_addr(0)), length_in_bytes); 106362587Sitojun } 1064120891Sume break; 1065120891Sume } 1066120891Sume case T_SHORT : { 106762587Sitojun if (Bytes::is_Java_byte_ordering_different()) { 106862587Sitojun WRITE_ARRAY(array, short, u2); 1069120891Sume } else { 107062587Sitojun writer->write_raw((void*)(array->short_at_addr(0)), length_in_bytes); 1071190964Srwatson } 1072120856Sume break; 107362587Sitojun } 107462587Sitojun case T_BOOLEAN : { 107562587Sitojun if (Bytes::is_Java_byte_ordering_different()) { 107662587Sitojun WRITE_ARRAY(array, bool, u1); 107762587Sitojun } else { 107862587Sitojun writer->write_raw((void*)(array->bool_at_addr(0)), length_in_bytes); 107962587Sitojun } 108062587Sitojun break; 108162587Sitojun } 108262587Sitojun case T_LONG : { 108362587Sitojun if (Bytes::is_Java_byte_ordering_different()) { 108462587Sitojun WRITE_ARRAY(array, long, u8); 108562587Sitojun } else { 108662587Sitojun writer->write_raw((void*)(array->long_at_addr(0)), length_in_bytes); 108753541Sshin } 108862587Sitojun break; 108962587Sitojun } 109095023Ssuz 109162587Sitojun // handle float/doubles in a special value to ensure than NaNs are 109262587Sitojun // written correctly. TO DO: Check if we can avoid this on processors that 109362587Sitojun // use IEEE 754. 109462587Sitojun 109562587Sitojun case T_FLOAT : { 109653541Sshin for (int i=0; i<array->length(); i++) { 109753541Sshin dump_float( writer, array->float_at(i) ); 109853541Sshin } 109978064Sume break; 110062587Sitojun } 110153541Sshin case T_DOUBLE : { 110262587Sitojun for (int i=0; i<array->length(); i++) { 110362587Sitojun dump_double( writer, array->double_at(i) ); 1104120891Sume } 110562587Sitojun break; 1106190964Srwatson } 1107120856Sume default : ShouldNotReachHere(); 110862587Sitojun } 110962587Sitojun} 111078064Sume 1111120891Sume// create a HPROF_FRAME record of the given Method* and bci 1112120891Sumevoid DumperSupport::dump_stack_frame(DumpWriter* writer, 1113120891Sume int frame_serial_num, 1114120891Sume int class_serial_num, 1115120891Sume Method* m, 1116120891Sume int bci) { 1117120891Sume int line_number; 1118120891Sume if (m->is_native()) { 111978064Sume line_number = -3; // native frame 1120120891Sume } else { 112178064Sume line_number = m->line_number_from_bci(bci); 112278064Sume } 112378064Sume 112478064Sume write_header(writer, HPROF_FRAME, 4*oopSize + 2*sizeof(u4)); 112578064Sume writer->write_id(frame_serial_num); // frame serial number 112678064Sume writer->write_symbolID(m->name()); // method's name 112778064Sume writer->write_symbolID(m->signature()); // method's signature 1128148385Sume 1129121315Sume assert(m->method_holder()->is_instance_klass(), "not InstanceKlass"); 113078064Sume writer->write_symbolID(m->method_holder()->source_file_name()); // source file name 113178064Sume writer->write_u4(class_serial_num); // class serial number 113278064Sume writer->write_u4((u4) line_number); // line number 113378064Sume} 1134148385Sume 1135121315Sume 1136148385Sume// Support class used to generate HPROF_UTF8 records from the entries in the 1137148385Sume// SymbolTable. 113878064Sume 113978064Sumeclass SymbolTableDumper : public SymbolClosure { 114078064Sume private: 114178064Sume DumpWriter* _writer; 114278064Sume DumpWriter* writer() const { return _writer; } 114378064Sume public: 114478064Sume SymbolTableDumper(DumpWriter* writer) { _writer = writer; } 114578064Sume void do_symbol(Symbol** p); 114678064Sume}; 114778064Sume 114878064Sumevoid SymbolTableDumper::do_symbol(Symbol** p) { 114962587Sitojun ResourceMark rm; 115078064Sume Symbol* sym = load_symbol(p); 115178064Sume int len = sym->utf8_length(); 115278064Sume if (len > 0) { 115362587Sitojun char* s = sym->as_utf8(); 115462587Sitojun DumperSupport::write_header(writer(), HPROF_UTF8, oopSize + len); 1155175162Sobrien writer()->write_symbolID(sym); 1156120891Sume writer()->write_raw(s, len); 115753541Sshin } 115878064Sume} 1159120891Sume 116053541Sshin// Support class used to generate HPROF_GC_ROOT_JNI_LOCAL records 116153541Sshin 1162142681Sumeclass JNILocalsDumper : public OopClosure { 1163120856Sume private: 116453541Sshin DumpWriter* _writer; 116578064Sume u4 _thread_serial_num; 116653541Sshin int _frame_num; 1167120856Sume DumpWriter* writer() const { return _writer; } 116853541Sshin public: 116953541Sshin JNILocalsDumper(DumpWriter* writer, u4 thread_serial_num) { 117078064Sume _writer = writer; 1171171259Sdelphij _thread_serial_num = thread_serial_num; 117262587Sitojun _frame_num = -1; // default - empty stack 117378064Sume } 117478064Sume void set_frame_number(int n) { _frame_num = n; } 117578064Sume void do_oop(oop* obj_p); 117662587Sitojun void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); } 1177122922Sandre}; 117862587Sitojun 1179121472Sume 1180121472Sumevoid JNILocalsDumper::do_oop(oop* obj_p) { 1181121472Sume // ignore null or deleted handles 1182121472Sume oop o = *obj_p; 1183121472Sume if (o != NULL && o != JNIHandles::deleted_handle()) { 1184121472Sume writer()->write_u1(HPROF_GC_ROOT_JNI_LOCAL); 1185121472Sume writer()->write_objectID(o); 1186121472Sume writer()->write_u4(_thread_serial_num); 1187121472Sume writer()->write_u4((u4)_frame_num); 1188121472Sume } 1189121472Sume} 1190121472Sume 1191121472Sume 1192121472Sume// Support class used to generate HPROF_GC_ROOT_JNI_GLOBAL records 1193121472Sume 1194121472Sumeclass JNIGlobalsDumper : public OopClosure { 1195121472Sume private: 1196121472Sume DumpWriter* _writer; 1197121472Sume DumpWriter* writer() const { return _writer; } 1198121472Sume 119978064Sume public: 120078064Sume JNIGlobalsDumper(DumpWriter* writer) { 120178064Sume _writer = writer; 1202182740Ssimon } 1203182740Ssimon void do_oop(oop* obj_p); 1204182740Ssimon void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); } 1205182740Ssimon}; 1206182740Ssimon 1207182740Ssimonvoid JNIGlobalsDumper::do_oop(oop* obj_p) { 1208182740Ssimon oop o = *obj_p; 1209182740Ssimon 1210182740Ssimon // ignore these 1211122922Sandre if (o == NULL || o == JNIHandles::deleted_handle()) return; 1212257084Sae 1213186222Sbz // we ignore global ref to symbols and other internal objects 1214122922Sandre if (o->is_instance() || o->is_objArray() || o->is_typeArray()) { 1215148385Sume writer()->write_u1(HPROF_GC_ROOT_JNI_GLOBAL); 1216148385Sume writer()->write_objectID(o); 121762587Sitojun writer()->write_objectID((oopDesc*)obj_p); // global ref ID 1218162084Sandre } 1219122922Sandre}; 1220190964Srwatson 122162587Sitojun 122262587Sitojun// Support class used to generate HPROF_GC_ROOT_MONITOR_USED records 122362587Sitojun 122453541Sshinclass MonitorUsedDumper : public OopClosure { 122578064Sume private: 122678064Sume DumpWriter* _writer; 1227120891Sume DumpWriter* writer() const { return _writer; } 122862587Sitojun public: 122962587Sitojun MonitorUsedDumper(DumpWriter* writer) { 123062587Sitojun _writer = writer; 123162587Sitojun } 123262587Sitojun void do_oop(oop* obj_p) { 123362587Sitojun writer()->write_u1(HPROF_GC_ROOT_MONITOR_USED); 123453541Sshin writer()->write_objectID(*obj_p); 123553541Sshin } 1236171259Sdelphij void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); } 123753541Sshin}; 123862587Sitojun 123953541Sshin 1240193066Sjamie// Support class used to generate HPROF_GC_ROOT_STICKY_CLASS records 124162587Sitojun 124262587Sitojunclass StickyClassDumper : public KlassClosure { 124353541Sshin private: 124453541Sshin DumpWriter* _writer; 124553541Sshin DumpWriter* writer() const { return _writer; } 124653541Sshin public: 1247148385Sume StickyClassDumper(DumpWriter* writer) { 124862587Sitojun _writer = writer; 124962587Sitojun } 125078064Sume void do_klass(Klass* k) { 125178064Sume if (k->is_instance_klass()) { 125253541Sshin InstanceKlass* ik = InstanceKlass::cast(k); 125362587Sitojun writer()->write_u1(HPROF_GC_ROOT_STICKY_CLASS); 125462587Sitojun writer()->write_classID(ik); 125562587Sitojun } 125662587Sitojun } 125762587Sitojun}; 125862587Sitojun 125962587Sitojun 1260120891Sumeclass VM_HeapDumper; 126162587Sitojun 126262587Sitojun// Support class using when iterating over the heap. 126353541Sshin 126462587Sitojunclass HeapObjectDumper : public ObjectClosure { 1265169664Sjinmei private: 1266169664Sjinmei VM_HeapDumper* _dumper; 1267169664Sjinmei DumpWriter* _writer; 1268169664Sjinmei 1269169664Sjinmei VM_HeapDumper* dumper() { return _dumper; } 1270169664Sjinmei DumpWriter* writer() { return _writer; } 1271169664Sjinmei 1272169664Sjinmei // used to indicate that a record has been writen 1273169664Sjinmei void mark_end_of_record(); 1274169664Sjinmei 1275169664Sjinmei public: 1276169664Sjinmei HeapObjectDumper(VM_HeapDumper* dumper, DumpWriter* writer) { 1277181803Sbz _dumper = dumper; 1278169664Sjinmei _writer = writer; 1279169664Sjinmei } 1280169664Sjinmei 1281169664Sjinmei // called for each object in the heap 1282169664Sjinmei void do_object(oop o); 128362587Sitojun}; 128462587Sitojun 128578064Sumevoid HeapObjectDumper::do_object(oop o) { 128678064Sume // hide the sentinel for deleted handles 128778064Sume if (o == JNIHandles::deleted_handle()) return; 1288169664Sjinmei 128962587Sitojun // skip classes as these emitted as HPROF_GC_CLASS_DUMP records 1290121630Sume if (o->klass() == SystemDictionary::Class_klass()) { 1291121630Sume if (!java_lang_Class::is_primitive(o)) { 1292121630Sume return; 1293121630Sume } 1294121630Sume } 1295274300Sae 1296274300Sae // create a HPROF_GC_INSTANCE record for each object 1297121630Sume if (o->is_instance()) { 1298121630Sume DumperSupport::dump_instance(writer(), o); 1299121630Sume mark_end_of_record(); 1300181803Sbz } else { 1301194760Srwatson // create a HPROF_GC_OBJ_ARRAY_DUMP record for each object array 130278064Sume if (o->is_objArray()) { 130378064Sume DumperSupport::dump_object_array(writer(), objArrayOop(o)); 130478064Sume mark_end_of_record(); 130578064Sume } else { 130678064Sume // create a HPROF_GC_PRIM_ARRAY_DUMP record for each type array 1307194760Srwatson if (o->is_typeArray()) { 1308121630Sume DumperSupport::dump_prim_array(writer(), typeArrayOop(o)); 130962587Sitojun mark_end_of_record(); 131078064Sume } 131162587Sitojun } 131262587Sitojun } 131362587Sitojun} 131462587Sitojun 131562587Sitojun// The VM operation that performs the heap dump 131678064Sumeclass VM_HeapDumper : public VM_GC_Operation { 131778064Sume private: 131878064Sume static VM_HeapDumper* _global_dumper; 131978064Sume static DumpWriter* _global_writer; 132062587Sitojun DumpWriter* _local_writer; 132162587Sitojun JavaThread* _oome_thread; 1322151475Ssuz Method* _oome_constructor; 132362587Sitojun bool _gc_before_heap_dump; 132462587Sitojun bool _is_segmented_dump; 132562587Sitojun jlong _dump_start; 132662587Sitojun GrowableArray<Klass*>* _klass_map; 132762587Sitojun ThreadStackTrace** _stack_traces; 132862587Sitojun int _num_threads; 132962587Sitojun 133062587Sitojun // accessors and setters 133162587Sitojun static VM_HeapDumper* dumper() { assert(_global_dumper != NULL, "Error"); return _global_dumper; } 133278064Sume static DumpWriter* writer() { assert(_global_writer != NULL, "Error"); return _global_writer; } 133378064Sume void set_global_dumper() { 133462587Sitojun assert(_global_dumper == NULL, "Error"); 133562587Sitojun _global_dumper = this; 133662587Sitojun } 133778064Sume void set_global_writer() { 133878064Sume assert(_global_writer == NULL, "Error"); 133978064Sume _global_writer = _local_writer; 134078064Sume } 134162587Sitojun void clear_global_dumper() { _global_dumper = NULL; } 1342121630Sume void clear_global_writer() { _global_writer = NULL; } 134362587Sitojun 134462587Sitojun bool is_segmented_dump() const { return _is_segmented_dump; } 134562587Sitojun void set_segmented_dump() { _is_segmented_dump = true; } 134662587Sitojun jlong dump_start() const { return _dump_start; } 134762587Sitojun void set_dump_start(jlong pos); 134878064Sume 134978064Sume bool skip_operation() const; 135062587Sitojun 135162587Sitojun // writes a HPROF_LOAD_CLASS record 135262587Sitojun static void do_load_class(Klass* k); 135362587Sitojun 135462587Sitojun // writes a HPROF_GC_CLASS_DUMP record for the given class 135562587Sitojun // (and each array class too) 135662587Sitojun static void do_class_dump(Klass* k); 135762587Sitojun 135862587Sitojun // writes a HPROF_GC_CLASS_DUMP records for a given basic type 135962587Sitojun // array (and each multi-dimensional array too) 136062587Sitojun static void do_basic_type_array_class_dump(Klass* k); 1361148385Sume 1362148385Sume // HPROF_GC_ROOT_THREAD_OBJ records 1363121315Sume int do_thread(JavaThread* thread, u4 thread_serial_num); 1364121630Sume void do_threads(); 1365148385Sume 1366148385Sume void add_class_serial_number(Klass* k, int serial_num) { 136762587Sitojun _klass_map->at_put_grow(serial_num, k); 136878064Sume } 136962587Sitojun 137062587Sitojun // HPROF_TRACE and HPROF_FRAME records 137162587Sitojun void dump_stack_traces(); 137262587Sitojun 1373120891Sume // writes a HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT record 1374120891Sume void write_dump_header(); 137562587Sitojun 137662587Sitojun // fixes up the length of the current dump record 137762587Sitojun void write_current_dump_record_length(); 137862587Sitojun 137962587Sitojun // fixes up the current dump record )and writes HPROF_HEAP_DUMP_END 138062587Sitojun // record in the case of a segmented heap dump) 138162587Sitojun void end_of_dump(); 138262587Sitojun 138362587Sitojun public: 138462587Sitojun VM_HeapDumper(DumpWriter* writer, bool gc_before_heap_dump, bool oome) : 138562587Sitojun VM_GC_Operation(0 /* total collections, dummy, ignored */, 138662587Sitojun GCCause::_heap_dump /* GC Cause */, 138762587Sitojun 0 /* total full collections, dummy, ignored */, 138862587Sitojun gc_before_heap_dump) { 138962587Sitojun _local_writer = writer; 139062587Sitojun _gc_before_heap_dump = gc_before_heap_dump; 139162587Sitojun _is_segmented_dump = false; 1392193066Sjamie _dump_start = (jlong)-1; 1393193066Sjamie _klass_map = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<Klass*>(INITIAL_CLASS_COUNT, true); 1394194118Sjamie _stack_traces = NULL; 1395194118Sjamie _num_threads = 0; 1396193066Sjamie if (oome) { 139762587Sitojun assert(!Thread::current()->is_VM_thread(), "Dump from OutOfMemoryError cannot be called by the VMThread"); 139862587Sitojun // get OutOfMemoryError zero-parameter constructor 139962587Sitojun InstanceKlass* oome_ik = SystemDictionary::OutOfMemoryError_klass(); 140062587Sitojun _oome_constructor = oome_ik->find_method(vmSymbols::object_initializer_name(), 140162587Sitojun vmSymbols::void_method_signature()); 140262587Sitojun // get thread throwing OOME when generating the heap dump at OOME 140362587Sitojun _oome_thread = JavaThread::current(); 1404120891Sume } else { 140562587Sitojun _oome_thread = NULL; 140662587Sitojun _oome_constructor = NULL; 140762587Sitojun } 140862587Sitojun } 140962587Sitojun ~VM_HeapDumper() { 141062587Sitojun if (_stack_traces != NULL) { 141178064Sume for (int i=0; i < _num_threads; i++) { 141262587Sitojun delete _stack_traces[i]; 141362587Sitojun } 141462587Sitojun FREE_C_HEAP_ARRAY(ThreadStackTrace*, _stack_traces); 141562587Sitojun } 141678064Sume delete _klass_map; 141762587Sitojun } 141878064Sume 141978064Sume VMOp_Type type() const { return VMOp_HeapDumper; } 142078064Sume // used to mark sub-record boundary 1421181803Sbz void check_segment_length(); 142278064Sume void doit(); 142378064Sume}; 142478064Sume 1425151475SsuzVM_HeapDumper* VM_HeapDumper::_global_dumper = NULL; 1426181803SbzDumpWriter* VM_HeapDumper::_global_writer = NULL; 142778064Sume 142878064Sumebool VM_HeapDumper::skip_operation() const { 142978064Sume return false; 143078064Sume} 143178064Sume 143278064Sume// sets the dump starting position 143378064Sumevoid VM_HeapDumper::set_dump_start(jlong pos) { 143478064Sume _dump_start = pos; 143578064Sume} 143678064Sume 143778064Sume // writes a HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT record 143878064Sumevoid VM_HeapDumper::write_dump_header() { 143978064Sume if (writer()->is_open()) { 144078064Sume if (is_segmented_dump()) { 144178064Sume writer()->write_u1(HPROF_HEAP_DUMP_SEGMENT); 144278064Sume } else { 1443148892Sume writer()->write_u1(HPROF_HEAP_DUMP); 144478064Sume } 1445120891Sume writer()->write_u4(0); // current ticks 144678064Sume 144778064Sume // record the starting position for the dump (its length will be fixed up later) 1448151475Ssuz set_dump_start(writer()->current_offset()); 1449151475Ssuz writer()->write_u4(0); 1450151475Ssuz } 145162587Sitojun} 145278064Sume 145378064Sume// fixes up the length of the current dump record 1454120891Sumevoid VM_HeapDumper::write_current_dump_record_length() { 145578064Sume if (writer()->is_open()) { 145678064Sume assert(dump_start() >= 0, "no dump start recorded"); 145778064Sume 145878064Sume // calculate the size of the dump record 145978064Sume jlong dump_end = writer()->current_offset(); 146078064Sume jlong dump_len = (dump_end - dump_start() - 4); 146178064Sume 146278064Sume // record length must fit in a u4 146378064Sume if (dump_len > (jlong)(4L*(jlong)G)) { 146478064Sume warning("record is too large"); 146578064Sume } 146662587Sitojun 146762587Sitojun // seek to the dump start and fix-up the length 1468248328Sglebius writer()->seek_to_offset(dump_start()); 1469248328Sglebius writer()->write_u4((u4)dump_len); 1470248328Sglebius 1471248328Sglebius // adjust the total size written to keep the bytes written correct. 1472248328Sglebius writer()->adjust_bytes_written(-((long) sizeof(u4))); 1473248328Sglebius 1474248328Sglebius // seek to dump end so we can continue 1475248328Sglebius writer()->seek_to_offset(dump_end); 1476248328Sglebius 1477248328Sglebius // no current dump record 1478248328Sglebius set_dump_start((jlong)-1); 1479248328Sglebius } 148062587Sitojun} 148162587Sitojun 1482120856Sume// used on a sub-record boundary to check if we need to start a 148362587Sitojun// new segment. 1484248328Sglebiusvoid VM_HeapDumper::check_segment_length() { 148553541Sshin if (writer()->is_open()) { 148653541Sshin if (is_segmented_dump()) { 148753541Sshin // don't use current_offset that would be too expensive on a per record basis 148853541Sshin jlong dump_end = writer()->bytes_written() + writer()->bytes_unwritten(); 148953541Sshin assert(dump_end == writer()->current_offset(), "checking"); 149062587Sitojun jlong dump_len = (dump_end - dump_start() - 4); 149153541Sshin assert(dump_len >= 0 && dump_len <= max_juint, "bad dump length"); 149253541Sshin 149353541Sshin if (dump_len > (jlong)HeapDumpSegmentSize) { 149462587Sitojun write_current_dump_record_length(); 149578064Sume write_dump_header(); 149662587Sitojun } 149762587Sitojun } 149862587Sitojun } 149978064Sume} 150078064Sume 150178064Sume// fixes up the current dump record )and writes HPROF_HEAP_DUMP_END 150278064Sume// record in the case of a segmented heap dump) 150378064Sumevoid VM_HeapDumper::end_of_dump() { 150478064Sume if (writer()->is_open()) { 150578064Sume write_current_dump_record_length(); 150662587Sitojun 150778064Sume // for segmented dump we write the end record 150862587Sitojun if (is_segmented_dump()) { 150978064Sume writer()->write_u1(HPROF_HEAP_DUMP_END); 151062587Sitojun writer()->write_u4(0); 1511120891Sume writer()->write_u4(0); 151262587Sitojun } 151362587Sitojun } 151462587Sitojun} 1515193066Sjamie 151662587Sitojun// marks sub-record boundary 1517193066Sjamievoid HeapObjectDumper::mark_end_of_record() { 1518193066Sjamie dumper()->check_segment_length(); 1519194118Sjamie} 1520194118Sjamie 1521193066Sjamie// writes a HPROF_LOAD_CLASS record for the class (and each of its 152262587Sitojun// array classes) 152362587Sitojunvoid VM_HeapDumper::do_load_class(Klass* k) { 152462587Sitojun static u4 class_serial_num = 0; 152562587Sitojun 152662587Sitojun // len of HPROF_LOAD_CLASS record 152762587Sitojun u4 remaining = 2*oopSize + 2*sizeof(u4); 152862587Sitojun 152962587Sitojun // write a HPROF_LOAD_CLASS for the class and each array class 153062587Sitojun do { 153162587Sitojun DumperSupport::write_header(writer(), HPROF_LOAD_CLASS, remaining); 153253541Sshin 153378064Sume // class serial number is just a number 153478064Sume writer()->write_u4(++class_serial_num); 153578064Sume 153678064Sume // class ID 153762587Sitojun Klass* klass = k; 153862587Sitojun writer()->write_classID(klass); 153962587Sitojun 1540120891Sume // add the Klass* and class serial number pair 154162587Sitojun dumper()->add_class_serial_number(klass, class_serial_num); 154253541Sshin 154362587Sitojun writer()->write_u4(STACK_TRACE_ID); 154462587Sitojun 154562587Sitojun // class name ID 154653541Sshin Symbol* name = klass->name(); 154753541Sshin writer()->write_symbolID(name); 154862587Sitojun 1549120856Sume // write a LOAD_CLASS record for the array type (if it exists) 155053541Sshin k = klass->array_klass_or_null(); 155153541Sshin } while (k != NULL); 155262587Sitojun} 155353541Sshin 155453541Sshin// writes a HPROF_GC_CLASS_DUMP record for the given class 1555120856Sumevoid VM_HeapDumper::do_class_dump(Klass* k) { 155653541Sshin if (k->is_instance_klass()) { 155753541Sshin DumperSupport::dump_class_and_array_classes(writer(), k); 155853541Sshin } 155962587Sitojun} 156062587Sitojun 156162587Sitojun// writes a HPROF_GC_CLASS_DUMP records for a given basic type 156262587Sitojun// array (and each multi-dimensional array too) 1563171259Sdelphijvoid VM_HeapDumper::do_basic_type_array_class_dump(Klass* k) { 1564171259Sdelphij DumperSupport::dump_basic_type_array_class(writer(), k); 156562587Sitojun} 156662587Sitojun 1567171259Sdelphij// Walk the stack of the given thread. 156862587Sitojun// Dumps a HPROF_GC_ROOT_JAVA_FRAME record for each local 156962587Sitojun// Dumps a HPROF_GC_ROOT_JNI_LOCAL record for each JNI local 157062587Sitojun// 157162587Sitojun// It returns the number of Java frames in this thread stack 157262587Sitojunint VM_HeapDumper::do_thread(JavaThread* java_thread, u4 thread_serial_num) { 157362587Sitojun JNILocalsDumper blk(writer(), thread_serial_num); 157462587Sitojun 157562587Sitojun oop threadObj = java_thread->threadObj(); 157662587Sitojun assert(threadObj != NULL, "sanity check"); 157762587Sitojun 157862587Sitojun int stack_depth = 0; 1579248321Sglebius if (java_thread->has_last_Java_frame()) { 1580248321Sglebius 1581248321Sglebius // vframes are resource allocated 1582248321Sglebius Thread* current_thread = Thread::current(); 1583248321Sglebius ResourceMark rm(current_thread); 1584248321Sglebius HandleMark hm(current_thread); 158562587Sitojun 158662587Sitojun RegisterMap reg_map(java_thread); 158762587Sitojun frame f = java_thread->last_frame(); 158862587Sitojun vframe* vf = vframe::new_vframe(&f, ®_map, java_thread); 158962587Sitojun frame* last_entry_frame = NULL; 159062587Sitojun int extra_frames = 0; 159162587Sitojun 159262587Sitojun if (java_thread == _oome_thread && _oome_constructor != NULL) { 159362587Sitojun extra_frames++; 159462587Sitojun } 159562587Sitojun while (vf != NULL) { 159662587Sitojun blk.set_frame_number(stack_depth); 159762587Sitojun if (vf->is_java_frame()) { 159862587Sitojun 159962587Sitojun // java frame (interpreted, compiled, ...) 160062587Sitojun javaVFrame *jvf = javaVFrame::cast(vf); 160162587Sitojun if (!(jvf->method()->is_native())) { 160262587Sitojun StackValueCollection* locals = jvf->locals(); 160362587Sitojun for (int slot=0; slot<locals->size(); slot++) { 160462587Sitojun if (locals->at(slot)->type() == T_OBJECT) { 160562587Sitojun oop o = locals->obj_at(slot)(); 160662587Sitojun 160762587Sitojun if (o != NULL) { 160862587Sitojun writer()->write_u1(HPROF_GC_ROOT_JAVA_FRAME); 160962587Sitojun writer()->write_objectID(o); 161062587Sitojun writer()->write_u4(thread_serial_num); 161162587Sitojun writer()->write_u4((u4) (stack_depth + extra_frames)); 161262587Sitojun } 161362587Sitojun } 161462587Sitojun } 161562587Sitojun StackValueCollection *exprs = jvf->expressions(); 161662587Sitojun for(int index = 0; index < exprs->size(); index++) { 161762587Sitojun if (exprs->at(index)->type() == T_OBJECT) { 161862587Sitojun oop o = exprs->obj_at(index)(); 161962587Sitojun if (o != NULL) { 162062587Sitojun writer()->write_u1(HPROF_GC_ROOT_JAVA_FRAME); 162162587Sitojun writer()->write_objectID(o); 162262587Sitojun writer()->write_u4(thread_serial_num); 162378704Sume writer()->write_u4((u4) (stack_depth + extra_frames)); 162478704Sume } 162578704Sume } 162678704Sume } 162778704Sume } else { 162878704Sume // native frame 162962587Sitojun if (stack_depth == 0) { 163062587Sitojun // JNI locals for the top frame. 163162587Sitojun java_thread->active_handles()->oops_do(&blk); 163262587Sitojun } else { 163362587Sitojun if (last_entry_frame != NULL) { 163462587Sitojun // JNI locals for the entry frame 163562587Sitojun assert(last_entry_frame->is_entry_frame(), "checking"); 163662587Sitojun last_entry_frame->entry_frame_call_wrapper()->handles()->oops_do(&blk); 163762587Sitojun } 163862587Sitojun } 163962587Sitojun } 164062587Sitojun // increment only for Java frames 164162587Sitojun stack_depth++; 164262587Sitojun last_entry_frame = NULL; 164362587Sitojun 164462587Sitojun } else { 164562587Sitojun // externalVFrame - if it's an entry frame then report any JNI locals 164662587Sitojun // as roots when we find the corresponding native javaVFrame 164795023Ssuz frame* fr = vf->frame_pointer(); 164862587Sitojun assert(fr != NULL, "sanity check"); 164962587Sitojun if (fr->is_entry_frame()) { 165062587Sitojun last_entry_frame = fr; 165162587Sitojun } 165262587Sitojun } 165362587Sitojun vf = vf->sender(); 165462587Sitojun } 165562587Sitojun } else { 165662587Sitojun // no last java frame but there may be JNI locals 165762587Sitojun java_thread->active_handles()->oops_do(&blk); 165878064Sume } 165962587Sitojun return stack_depth; 166062587Sitojun} 1661171259Sdelphij 166262587Sitojun 166362587Sitojun// write a HPROF_GC_ROOT_THREAD_OBJ record for each java thread. Then walk 166462587Sitojun// the stack so that locals and JNI locals are dumped. 166562587Sitojunvoid VM_HeapDumper::do_threads() { 166662587Sitojun for (int i=0; i < _num_threads; i++) { 166762587Sitojun JavaThread* thread = _stack_traces[i]->thread(); 166862587Sitojun oop threadObj = thread->threadObj(); 166962587Sitojun u4 thread_serial_num = i+1; 167062587Sitojun u4 stack_serial_num = thread_serial_num + STACK_TRACE_ID; 167162587Sitojun writer()->write_u1(HPROF_GC_ROOT_THREAD_OBJ); 167262587Sitojun writer()->write_objectID(threadObj); 167362587Sitojun writer()->write_u4(thread_serial_num); // thread number 167462587Sitojun writer()->write_u4(stack_serial_num); // stack trace serial number 167562587Sitojun int num_frames = do_thread(thread, thread_serial_num); 167662587Sitojun assert(num_frames == _stack_traces[i]->get_stack_depth(), 167762587Sitojun "total number of Java frames not matched"); 167862587Sitojun } 167962587Sitojun} 168062587Sitojun 168162587Sitojun 168262587Sitojun// The VM operation that dumps the heap. The dump consists of the following 168362587Sitojun// records: 168462587Sitojun// 168562587Sitojun// HPROF_HEADER 168662587Sitojun// [HPROF_UTF8]* 168762587Sitojun// [HPROF_LOAD_CLASS]* 168862587Sitojun// [[HPROF_FRAME]*|HPROF_TRACE]* 168962587Sitojun// [HPROF_GC_CLASS_DUMP]* 169062587Sitojun// HPROF_HEAP_DUMP 169162587Sitojun// 169262587Sitojun// The HPROF_TRACE records represent the stack traces where the heap dump 169362587Sitojun// is generated and a "dummy trace" record which does not include 169462587Sitojun// any frames. The dummy trace record is used to be referenced as the 169562587Sitojun// unknown object alloc site. 169662587Sitojun// 169762587Sitojun// The HPROF_HEAP_DUMP record has a length following by sub-records. To allow 169862587Sitojun// the heap dump be generated in a single pass we remember the position of 169962587Sitojun// the dump length and fix it up after all sub-records have been written. 170062587Sitojun// To generate the sub-records we iterate over the heap, writing 170162587Sitojun// HPROF_GC_INSTANCE_DUMP, HPROF_GC_OBJ_ARRAY_DUMP, and HPROF_GC_PRIM_ARRAY_DUMP 170262587Sitojun// records as we go. Once that is done we write records for some of the GC 170362587Sitojun// roots. 170462587Sitojun 170562587Sitojunvoid VM_HeapDumper::doit() { 170662587Sitojun 170762587Sitojun HandleMark hm; 170862587Sitojun CollectedHeap* ch = Universe::heap(); 170962587Sitojun 171062587Sitojun ch->ensure_parsability(false); // must happen, even if collection does 171162587Sitojun // not happen (e.g. due to GC_locker) 171262587Sitojun 171362587Sitojun if (_gc_before_heap_dump) { 171462587Sitojun if (GC_locker::is_active()) { 171562587Sitojun warning("GC locker is held; pre-heapdump GC was skipped"); 171662587Sitojun } else { 171762587Sitojun ch->collect_as_vm_thread(GCCause::_heap_dump); 171853541Sshin } 171953541Sshin } 172053541Sshin 1721171259Sdelphij // At this point we should be the only dumper active, so 1722171259Sdelphij // the following should be safe. 172353541Sshin set_global_dumper(); 172478064Sume set_global_writer(); 172578064Sume 172678064Sume // Write the file header - use 1.0.2 for large heaps, otherwise 1.0.1 172753541Sshin size_t used = ch->used(); 172878064Sume const char* header; 172953541Sshin if (used > SegmentedHeapDumpThreshold) { 173078064Sume set_segmented_dump(); 173178064Sume header = "JAVA PROFILE 1.0.2"; 173278064Sume } else { 173378064Sume header = "JAVA PROFILE 1.0.1"; 1734120856Sume } 173578064Sume 173678064Sume // header is few bytes long - no chance to overflow int 173778064Sume writer()->write_raw((void*)header, (int)strlen(header)); 173878064Sume writer()->write_u1(0); // terminator 173978064Sume writer()->write_u4(oopSize); 174078064Sume writer()->write_u8(os::javaTimeMillis()); 1741120856Sume 174278064Sume // HPROF_UTF8 records 174378064Sume SymbolTableDumper sym_dumper(writer()); 174478064Sume SymbolTable::symbols_do(&sym_dumper); 1745196481Srwatson 1746274345Sglebius // write HPROF_LOAD_CLASS records 174753541Sshin ClassLoaderDataGraph::classes_do(&do_load_class); 1748229621Sjhb Universe::basic_type_classes_do(&do_load_class); 1749191340Srwatson 175053541Sshin // write HPROF_FRAME and HPROF_TRACE records 175153541Sshin // this must be called after _klass_map is built when iterating the classes above. 175253541Sshin dump_stack_traces(); 175353541Sshin 175478064Sume // write HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT 1755148892Sume write_dump_header(); 175653541Sshin 175753541Sshin // Writes HPROF_GC_CLASS_DUMP records 175862587Sitojun ClassLoaderDataGraph::classes_do(&do_class_dump); 175962587Sitojun Universe::basic_type_classes_do(&do_basic_type_array_class_dump); 176062587Sitojun check_segment_length(); 176162587Sitojun 176262587Sitojun // writes HPROF_GC_INSTANCE_DUMP records. 176378064Sume // After each sub-record is written check_segment_length will be invoked. When 176462587Sitojun // generated a segmented heap dump this allows us to check if the current 176562587Sitojun // segment exceeds a threshold and if so, then a new segment is started. 176662587Sitojun // The HPROF_GC_CLASS_DUMP and HPROF_GC_INSTANCE_DUMP are the vast bulk 176762587Sitojun // of the heap dump. 176853541Sshin HeapObjectDumper obj_dumper(this, writer()); 176978064Sume Universe::heap()->safe_object_iterate(&obj_dumper); 177078064Sume 177178064Sume // HPROF_GC_ROOT_THREAD_OBJ + frames + jni locals 177278064Sume do_threads(); 177353541Sshin check_segment_length(); 177478064Sume 177578064Sume // HPROF_GC_ROOT_MONITOR_USED 177678064Sume MonitorUsedDumper mon_dumper(writer()); 177753541Sshin ObjectSynchronizer::oops_do(&mon_dumper); 177878064Sume check_segment_length(); 177978064Sume 178078064Sume // HPROF_GC_ROOT_JNI_GLOBAL 178178064Sume JNIGlobalsDumper jni_dumper(writer()); 178278064Sume JNIHandles::oops_do(&jni_dumper); 178378064Sume check_segment_length(); 178453541Sshin 178578064Sume // HPROF_GC_ROOT_STICKY_CLASS 178678064Sume StickyClassDumper class_dumper(writer()); 178778064Sume SystemDictionary::always_strong_classes_do(&class_dumper); 178895023Ssuz 178978064Sume // fixes up the length of the dump record. In the case of a segmented 179078064Sume // heap then the HPROF_HEAP_DUMP_END record is also written. 179178064Sume end_of_dump(); 179278064Sume 179378064Sume // Now we clear the global variables, so that a future dumper might run. 1794181803Sbz clear_global_dumper(); 179578064Sume clear_global_writer(); 179678064Sume} 179778064Sume 179853541Sshinvoid VM_HeapDumper::dump_stack_traces() { 1799229621Sjhb // write a HPROF_TRACE record without any frames to be referenced as object alloc sites 180053541Sshin DumperSupport::write_header(writer(), HPROF_TRACE, 3*sizeof(u4)); 180153541Sshin writer()->write_u4((u4) STACK_TRACE_ID); 1802196481Srwatson writer()->write_u4(0); // thread number 1803120856Sume writer()->write_u4(0); // frame count 180453541Sshin 180553541Sshin _stack_traces = NEW_C_HEAP_ARRAY(ThreadStackTrace*, Threads::number_of_threads(), mtInternal); 180653541Sshin int frame_serial_num = 0; 180753541Sshin for (JavaThread* thread = Threads::first(); thread != NULL ; thread = thread->next()) { 1808196481Srwatson oop threadObj = thread->threadObj(); 180953541Sshin if (threadObj != NULL && !thread->is_exiting() && !thread->is_hidden_from_external_view()) { 1810120856Sume // dump thread stack trace 181153541Sshin ThreadStackTrace* stack_trace = new ThreadStackTrace(thread, false); 181253541Sshin stack_trace->dump_stack_at_safepoint(-1); 181353541Sshin _stack_traces[_num_threads++] = stack_trace; 1814171259Sdelphij 1815171259Sdelphij // write HPROF_FRAME records for this thread's stack trace 181653541Sshin int depth = stack_trace->get_stack_depth(); 1817228866Sjhb int thread_frame_start = frame_serial_num; 181878064Sume int extra_frames = 0; 181978064Sume // write fake frame that makes it look like the thread, which caused OOME, 182078064Sume // is in the OutOfMemoryError zero-parameter constructor 182178064Sume if (thread == _oome_thread && _oome_constructor != NULL) { 182253541Sshin int oome_serial_num = _klass_map->find(_oome_constructor->method_holder()); 182378064Sume // the class serial number starts from 1 182478064Sume assert(oome_serial_num > 0, "OutOfMemoryError class not found"); 182553541Sshin DumperSupport::dump_stack_frame(writer(), ++frame_serial_num, oome_serial_num, 182678064Sume _oome_constructor, 0); 1827120856Sume extra_frames++; 1828120891Sume } 1829196481Srwatson for (int j=0; j < depth; j++) { 1830228866Sjhb StackFrameInfo* frame = stack_trace->stack_frame_at(j); 183178064Sume Method* m = frame->method(); 1832120892Sume int class_serial_num = _klass_map->find(m->method_holder()); 1833274345Sglebius // the class serial number starts from 1 1834229621Sjhb assert(class_serial_num > 0, "class not found"); 1835191340Srwatson DumperSupport::dump_stack_frame(writer(), ++frame_serial_num, class_serial_num, m, frame->bci()); 183653541Sshin } 183753541Sshin depth += extra_frames; 183853541Sshin 183953541Sshin // write HPROF_TRACE record for one thread 184078064Sume DumperSupport::write_header(writer(), HPROF_TRACE, 3*sizeof(u4) + depth*oopSize); 184178064Sume int stack_serial_num = _num_threads + STACK_TRACE_ID; 184278064Sume writer()->write_u4(stack_serial_num); // stack trace serial number 184378064Sume writer()->write_u4((u4) _num_threads); // thread serial number 184478064Sume writer()->write_u4(depth); // frame count 184578064Sume for (int j=1; j <= depth; j++) { 184678064Sume writer()->write_id(thread_frame_start + j); 184778064Sume } 184878064Sume } 184978064Sume } 185078064Sume} 185178064Sume 1852120891Sume// dump the heap to given path. 1853120891Sumeint HeapDumper::dump(const char* path) { 185478064Sume assert(path != NULL && strlen(path) > 0, "path missing"); 185553541Sshin 185653541Sshin // print message in interactive case 185778064Sume if (print_to_tty()) { 185878064Sume tty->print_cr("Dumping heap to %s ...", path); 185978064Sume timer()->start(); 186078064Sume } 186153541Sshin 186278064Sume // create the dump writer. If the file can be opened then bail 186378064Sume DumpWriter writer(path); 186478064Sume if (!writer.is_open()) { 186553541Sshin set_error(writer.error()); 186678064Sume if (print_to_tty()) { 186778064Sume tty->print_cr("Unable to create %s: %s", path, 186878064Sume (error() != NULL) ? error() : "reason unknown"); 186978064Sume } 187078064Sume return -1; 187178064Sume } 187253541Sshin 187353541Sshin // generate the dump 187478064Sume VM_HeapDumper dumper(&writer, _gc_before_heap_dump, _oome); 187578064Sume if (Thread::current()->is_VM_thread()) { 1876120891Sume assert(SafepointSynchronize::is_at_safepoint(), "Expected to be called at a safepoint"); 187778064Sume dumper.doit(); 187878064Sume } else { 187978064Sume VMThread::execute(&dumper); 188078064Sume } 188178064Sume 1882181803Sbz // close dump file and record any error that the writer may have encountered 188378064Sume writer.close(); 188453541Sshin set_error(writer.error()); 188578064Sume 188678064Sume // print message in interactive case 188778064Sume if (print_to_tty()) { 188878064Sume timer()->stop(); 1889229621Sjhb if (error() == NULL) { 189078064Sume tty->print_cr("Heap dump file created [" JLONG_FORMAT " bytes in %3.3f secs]", 189178064Sume writer.bytes_written(), timer()->seconds()); 189278064Sume } else { 189378064Sume tty->print_cr("Dump file is incomplete: %s", writer.error()); 1894120891Sume } 1895196481Srwatson } 1896120856Sume 189778064Sume return (writer.error() == NULL) ? 0 : -1; 189878064Sume} 189978064Sume 190078064Sume// stop timer (if still active), and free any error string we might be holding 190178064SumeHeapDumper::~HeapDumper() { 190278064Sume if (timer()->is_active()) { 190378064Sume timer()->stop(); 190478064Sume } 190578064Sume set_error(NULL); 190678064Sume} 190778064Sume 190878064Sume 190978064Sume// returns the error string (resource allocated), or NULL 191078064Sumechar* HeapDumper::error_as_C_string() const { 191178064Sume if (error() != NULL) { 191278064Sume char* str = NEW_RESOURCE_ARRAY(char, strlen(error())+1); 191378064Sume strcpy(str, error()); 191478064Sume return str; 191578064Sume } else { 191678064Sume return NULL; 191778064Sume } 1918253970Shrs} 1919253970Shrs 192078064Sume// set the error string 192178064Sumevoid HeapDumper::set_error(char* error) { 192278064Sume if (_error != NULL) { 1923120891Sume os::free(_error); 192478064Sume } 192578064Sume if (error == NULL) { 192678064Sume _error = NULL; 192778064Sume } else { 192878064Sume _error = os::strdup(error); 1929120891Sume assert(_error != NULL, "allocation failure"); 1930121315Sume } 193178064Sume} 1932120891Sume 193378064Sume// Called by out-of-memory error reporting by a single Java thread 1934120891Sume// outside of a JVM safepoint 193553541Sshinvoid HeapDumper::dump_heap_from_oome() { 1936229621Sjhb HeapDumper::dump_heap(true); 193753541Sshin} 193853541Sshin 193953541Sshin// Called by error reporting by a single Java thread outside of a JVM safepoint, 194053541Sshin// or by heap dumping by the VM thread during a (GC) safepoint. Thus, these various 194178064Sume// callers are strictly serialized and guaranteed not to interfere below. For more 194278064Sume// general use, however, this method will need modification to prevent 194378064Sume// inteference when updating the static variables base_path and dump_file_seq below. 194478064Sumevoid HeapDumper::dump_heap() { 194578064Sume HeapDumper::dump_heap(false); 194678064Sume} 194778064Sume 1948196481Srwatsonvoid HeapDumper::dump_heap(bool oome) { 1949108172Shsu static char base_path[JVM_MAXPATHLEN] = {'\0'}; 1950120856Sume static uint dump_file_seq = 0; 195153541Sshin char* my_path; 195253541Sshin const int max_digit_chars = 20; 195353541Sshin 195453541Sshin const char* dump_file_name = "java_pid"; 195553541Sshin const char* dump_file_ext = ".hprof"; 195653541Sshin 1957171259Sdelphij // The dump file defaults to java_pid<pid>.hprof in the current working 195853541Sshin // directory. HeapDumpPath=<file> can be used to specify an alternative 195953541Sshin // dump file name or a directory where dump file is created. 196078064Sume if (dump_file_seq == 0) { // first time in, we initialize base_path 1961186141Sbz // Calculate potentially longest base path and check if we have enough 1962186141Sbz // allocated statically. 1963121315Sume const size_t total_length = 196453541Sshin (HeapDumpPath == NULL ? 0 : strlen(HeapDumpPath)) + 196553541Sshin strlen(os::file_separator()) + max_digit_chars + 196653541Sshin strlen(dump_file_name) + strlen(dump_file_ext) + 1; 196762587Sitojun if (total_length > sizeof(base_path)) { 196853541Sshin warning("Cannot create heap dump file. HeapDumpPath is too long."); 196953541Sshin return; 197062587Sitojun } 197162587Sitojun 197262587Sitojun bool use_default_filename = true; 197362587Sitojun if (HeapDumpPath == NULL || HeapDumpPath[0] == '\0') { 1974120891Sume // HeapDumpPath=<file> not specified 197562587Sitojun } else { 197662587Sitojun strcpy(base_path, HeapDumpPath); 197753541Sshin // check if the path is a directory (must exist) 1978148385Sume DIR* dir = os::opendir(base_path); 1979148385Sume if (dir == NULL) { 1980148385Sume use_default_filename = false; 1981148385Sume } else { 1982121315Sume // HeapDumpPath specified a directory. We append a file separator 1983148385Sume // (if needed). 1984121315Sume os::closedir(dir); 1985148385Sume size_t fs_len = strlen(os::file_separator()); 1986148385Sume if (strlen(base_path) >= fs_len) { 1987148385Sume char* end = base_path; 1988148385Sume end += (strlen(base_path) - fs_len); 1989148385Sume if (strcmp(end, os::file_separator()) != 0) { 199053541Sshin strcat(base_path, os::file_separator()); 1991181803Sbz } 1992181803Sbz } 1993180850Smav } 199453541Sshin } 1995186141Sbz // If HeapDumpPath wasn't a file name then we append the default name 1996180850Smav if (use_default_filename) { 199753541Sshin const size_t dlen = strlen(base_path); // if heap dump dir specified 199853541Sshin jio_snprintf(&base_path[dlen], sizeof(base_path)-dlen, "%s%d%s", 1999180850Smav dump_file_name, os::current_process_id(), dump_file_ext); 200053541Sshin } 200153541Sshin const size_t len = strlen(base_path) + 1; 2002180850Smav my_path = (char*)os::malloc(len, mtInternal); 2003180932Smav if (my_path == NULL) { 2004180965Srwatson warning("Cannot create heap dump file. Out of system memory."); 2005180965Srwatson return; 2006180932Smav } 2007180850Smav strncpy(my_path, base_path, len); 2008180932Smav } else { 2009186163Skmacy // Append a sequence number id for dumps following the first 2010121809Sume const size_t len = strlen(base_path) + max_digit_chars + 2; // for '.' and \0 2011121809Sume my_path = (char*)os::malloc(len, mtInternal); 2012121809Sume if (my_path == NULL) { 2013121809Sume warning("Cannot create heap dump file. Out of system memory."); 2014121809Sume return; 2015121809Sume } 2016121809Sume jio_snprintf(my_path, len, "%s.%d", base_path, dump_file_seq); 2017121809Sume } 2018121809Sume dump_file_seq++; // increment seq number for next time we dump 2019121809Sume 2020121809Sume HeapDumper dumper(false /* no GC before heap dump */, 2021121809Sume true /* send to tty */, 2022121809Sume oome /* pass along out-of-memory-error flag */); 2023121809Sume dumper.dump(my_path); 2024121809Sume os::free(my_path); 2025121809Sume} 2026121809Sume