8144732: VM_HeapDumper hits assert with bad dump_len jdk8u252-b01

Fri, 24 Jan 2020 09:41:30 +0800

author
aeriksso
date
Fri, 24 Jan 2020 09:41:30 +0800
changeset 9820
a67e9c6edcdd
parent 9819
cd47e690607d
child 9821
0cf14bdd73fe
child 9823
147dfbe6ffa1

8144732: VM_HeapDumper hits assert with bad dump_len
Reviewed-by: dsamersoff

src/share/vm/runtime/arguments.cpp file | annotate | diff | comparison | revisions
src/share/vm/services/heapDumper.cpp file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/vm/runtime/arguments.cpp	Fri Sep 27 16:23:12 2019 +0200
     1.2 +++ b/src/share/vm/runtime/arguments.cpp	Fri Jan 24 09:41:30 2020 +0800
     1.3 @@ -305,6 +305,7 @@
     1.4    { "UseOldInlining",                JDK_Version::jdk_update(8, 20), JDK_Version::jdk(10) },
     1.5    { "AutoShutdownNMT",               JDK_Version::jdk_update(8, 40), JDK_Version::jdk(10) },
     1.6    { "CompilationRepeat",             JDK_Version::jdk(8), JDK_Version::jdk(9) },
     1.7 +  { "SegmentedHeapDumpThreshold",    JDK_Version::jdk_update(8, 252), JDK_Version::jdk(10) },
     1.8  #ifdef PRODUCT
     1.9    { "DesiredMethodLimit",
    1.10                             JDK_Version::jdk_update(7, 2), JDK_Version::jdk(8) },
     2.1 --- a/src/share/vm/services/heapDumper.cpp	Fri Sep 27 16:23:12 2019 +0200
     2.2 +++ b/src/share/vm/services/heapDumper.cpp	Fri Jan 24 09:41:30 2020 +0800
     2.3 @@ -50,8 +50,7 @@
     2.4   *   src/share/demo/jvmti/hprof/hprof_io.c
     2.5   *
     2.6   *
     2.7 - *  header    "JAVA PROFILE 1.0.1" or "JAVA PROFILE 1.0.2"
     2.8 - *            (0-terminated)
     2.9 + *  header    "JAVA PROFILE 1.0.2" (0-terminated)
    2.10   *
    2.11   *  u4        size of identifiers. Identifiers are used to represent
    2.12   *            UTF8 strings, objects, stack traces, etc. They usually
    2.13 @@ -382,6 +381,8 @@
    2.14    size_t _size;
    2.15    size_t _pos;
    2.16  
    2.17 +  jlong _dump_start;
    2.18 +
    2.19    char* _error;   // error message when I/O fails
    2.20  
    2.21    void set_file_descriptor(int fd)              { _fd = fd; }
    2.22 @@ -405,6 +406,10 @@
    2.23    bool is_open() const                  { return file_descriptor() >= 0; }
    2.24    void flush();
    2.25  
    2.26 +  jlong dump_start() const                      { return _dump_start; }
    2.27 +  void set_dump_start(jlong pos);
    2.28 +  julong current_record_length();
    2.29 +
    2.30    // total number of bytes written to the disk
    2.31    julong bytes_written() const          { return _bytes_written; }
    2.32  
    2.33 @@ -446,6 +451,7 @@
    2.34    _pos = 0;
    2.35    _error = NULL;
    2.36    _bytes_written = 0L;
    2.37 +  _dump_start = (jlong)-1;
    2.38    _fd = os::create_binary_file(path, false);    // don't replace existing file
    2.39  
    2.40    // if the open failed we record the error
    2.41 @@ -473,6 +479,22 @@
    2.42    }
    2.43  }
    2.44  
    2.45 +// sets the dump starting position
    2.46 +void DumpWriter::set_dump_start(jlong pos) {
    2.47 +  _dump_start = pos;
    2.48 +}
    2.49 +
    2.50 +julong DumpWriter::current_record_length() {
    2.51 +  if (is_open()) {
    2.52 +    // calculate the size of the dump record
    2.53 +    julong dump_end = bytes_written() + bytes_unwritten();
    2.54 +    assert(dump_end == (size_t)current_offset(), "checking");
    2.55 +    julong dump_len = dump_end - dump_start() - 4;
    2.56 +    return dump_len;
    2.57 +  }
    2.58 +  return 0;
    2.59 +}
    2.60 +
    2.61  // write directly to the file
    2.62  void DumpWriter::write_internal(void* s, size_t len) {
    2.63    if (is_open()) {
    2.64 @@ -641,6 +663,18 @@
    2.65    static void dump_prim_array(DumpWriter* writer, typeArrayOop array);
    2.66    // create HPROF_FRAME record for the given method and bci
    2.67    static void dump_stack_frame(DumpWriter* writer, int frame_serial_num, int class_serial_num, Method* m, int bci);
    2.68 +
    2.69 +  // check if we need to truncate an array
    2.70 +  static int calculate_array_max_length(DumpWriter* writer, arrayOop array, short header_size);
    2.71 +
    2.72 +  // writes a HPROF_HEAP_DUMP_SEGMENT record
    2.73 +  static void write_dump_header(DumpWriter* writer);
    2.74 +
    2.75 +  // fixes up the length of the current dump record
    2.76 +  static void write_current_dump_record_length(DumpWriter* writer);
    2.77 +
    2.78 +  // fixes up the current dump record and writes HPROF_HEAP_DUMP_END record
    2.79 +  static void end_of_dump(DumpWriter* writer);
    2.80  };
    2.81  
    2.82  // write a header of the given type
    2.83 @@ -1047,50 +1081,103 @@
    2.84    }
    2.85  }
    2.86  
    2.87 +// Hprof uses an u4 as record length field,
    2.88 +// which means we need to truncate arrays that are too long.
    2.89 +int DumperSupport::calculate_array_max_length(DumpWriter* writer, arrayOop array, short header_size) {
    2.90 +  BasicType type = ArrayKlass::cast(array->klass())->element_type();
    2.91 +  assert(type >= T_BOOLEAN && type <= T_OBJECT, "invalid array element type");
    2.92 +
    2.93 +  int length = array->length();
    2.94 +
    2.95 +  int type_size;
    2.96 +  if (type == T_OBJECT) {
    2.97 +    type_size = sizeof(address);
    2.98 +  } else {
    2.99 +    type_size = type2aelembytes(type);
   2.100 +  }
   2.101 +
   2.102 +  size_t length_in_bytes = (size_t)length * type_size;
   2.103 +
   2.104 +  // Create a new record if the current record is non-empty and the array can't fit.
   2.105 +  julong current_record_length = writer->current_record_length();
   2.106 +  if (current_record_length > 0 &&
   2.107 +      (current_record_length + header_size + length_in_bytes) > max_juint) {
   2.108 +    write_current_dump_record_length(writer);
   2.109 +    write_dump_header(writer);
   2.110 +
   2.111 +    // We now have an empty record.
   2.112 +    current_record_length = 0;
   2.113 +  }
   2.114 +
   2.115 +  // Calculate max bytes we can use.
   2.116 +  uint max_bytes = max_juint - (header_size + current_record_length);
   2.117 +
   2.118 +  // Array too long for the record?
   2.119 +  // Calculate max length and return it.
   2.120 +  if (length_in_bytes > max_bytes) {
   2.121 +    length = max_bytes / type_size;
   2.122 +    length_in_bytes = (size_t)length * type_size;
   2.123 +
   2.124 +    warning("cannot dump array of type %s[] with length %d; truncating to length %d",
   2.125 +            type2name_tab[type], array->length(), length);
   2.126 +  }
   2.127 +  return length;
   2.128 +}
   2.129 +
   2.130  // creates HPROF_GC_OBJ_ARRAY_DUMP record for the given object array
   2.131  void DumperSupport::dump_object_array(DumpWriter* writer, objArrayOop array) {
   2.132 +  // sizeof(u1) + 2 * sizeof(u4) + sizeof(objectID) + sizeof(classID)
   2.133 +  short header_size = 1 + 2 * 4 + 2 * sizeof(address);
   2.134 +
   2.135 +  int length = calculate_array_max_length(writer, array, header_size);
   2.136  
   2.137    writer->write_u1(HPROF_GC_OBJ_ARRAY_DUMP);
   2.138    writer->write_objectID(array);
   2.139    writer->write_u4(STACK_TRACE_ID);
   2.140 -  writer->write_u4((u4)array->length());
   2.141 +  writer->write_u4(length);
   2.142 +
   2.143  
   2.144    // array class ID
   2.145    writer->write_classID(array->klass());
   2.146  
   2.147    // [id]* elements
   2.148 -  for (int index=0; index<array->length(); index++) {
   2.149 +  for (int index = 0; index < length; index++) {
   2.150      oop o = array->obj_at(index);
   2.151      writer->write_objectID(o);
   2.152    }
   2.153  }
   2.154  
   2.155 -#define WRITE_ARRAY(Array, Type, Size) \
   2.156 -  for (int i=0; i<Array->length(); i++) { writer->write_##Size((Size)array->Type##_at(i)); }
   2.157 -
   2.158 +#define WRITE_ARRAY(Array, Type, Size, Length) \
   2.159 +  for (int i = 0; i < Length; i++) { writer->write_##Size((Size)array->Type##_at(i)); }
   2.160  
   2.161  // creates HPROF_GC_PRIM_ARRAY_DUMP record for the given type array
   2.162  void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) {
   2.163    BasicType type = TypeArrayKlass::cast(array->klass())->element_type();
   2.164  
   2.165 +  // 2 * sizeof(u1) + 2 * sizeof(u4) + sizeof(objectID)
   2.166 +  short header_size = 2 * 1 + 2 * 4 + sizeof(address);
   2.167 +
   2.168 +  int length = calculate_array_max_length(writer, array, header_size);
   2.169 +  int type_size = type2aelembytes(type);
   2.170 +  u4 length_in_bytes = (u4)length * type_size;
   2.171 +
   2.172    writer->write_u1(HPROF_GC_PRIM_ARRAY_DUMP);
   2.173    writer->write_objectID(array);
   2.174    writer->write_u4(STACK_TRACE_ID);
   2.175 -  writer->write_u4((u4)array->length());
   2.176 +  writer->write_u4(length);
   2.177    writer->write_u1(type2tag(type));
   2.178  
   2.179    // nothing to copy
   2.180 -  if (array->length() == 0) {
   2.181 +  if (length == 0) {
   2.182      return;
   2.183    }
   2.184  
   2.185    // If the byte ordering is big endian then we can copy most types directly
   2.186 -  u4 length_in_bytes = (u4)array->length() * type2aelembytes(type);
   2.187  
   2.188    switch (type) {
   2.189      case T_INT : {
   2.190        if (Bytes::is_Java_byte_ordering_different()) {
   2.191 -        WRITE_ARRAY(array, int, u4);
   2.192 +        WRITE_ARRAY(array, int, u4, length);
   2.193        } else {
   2.194          writer->write_raw((void*)(array->int_at_addr(0)), length_in_bytes);
   2.195        }
   2.196 @@ -1102,7 +1189,7 @@
   2.197      }
   2.198      case T_CHAR : {
   2.199        if (Bytes::is_Java_byte_ordering_different()) {
   2.200 -        WRITE_ARRAY(array, char, u2);
   2.201 +        WRITE_ARRAY(array, char, u2, length);
   2.202        } else {
   2.203          writer->write_raw((void*)(array->char_at_addr(0)), length_in_bytes);
   2.204        }
   2.205 @@ -1110,7 +1197,7 @@
   2.206      }
   2.207      case T_SHORT : {
   2.208        if (Bytes::is_Java_byte_ordering_different()) {
   2.209 -        WRITE_ARRAY(array, short, u2);
   2.210 +        WRITE_ARRAY(array, short, u2, length);
   2.211        } else {
   2.212          writer->write_raw((void*)(array->short_at_addr(0)), length_in_bytes);
   2.213        }
   2.214 @@ -1118,7 +1205,7 @@
   2.215      }
   2.216      case T_BOOLEAN : {
   2.217        if (Bytes::is_Java_byte_ordering_different()) {
   2.218 -        WRITE_ARRAY(array, bool, u1);
   2.219 +        WRITE_ARRAY(array, bool, u1, length);
   2.220        } else {
   2.221          writer->write_raw((void*)(array->bool_at_addr(0)), length_in_bytes);
   2.222        }
   2.223 @@ -1126,7 +1213,7 @@
   2.224      }
   2.225      case T_LONG : {
   2.226        if (Bytes::is_Java_byte_ordering_different()) {
   2.227 -        WRITE_ARRAY(array, long, u8);
   2.228 +        WRITE_ARRAY(array, long, u8, length);
   2.229        } else {
   2.230          writer->write_raw((void*)(array->long_at_addr(0)), length_in_bytes);
   2.231        }
   2.232 @@ -1138,14 +1225,14 @@
   2.233      // use IEEE 754.
   2.234  
   2.235      case T_FLOAT : {
   2.236 -      for (int i=0; i<array->length(); i++) {
   2.237 -        dump_float( writer, array->float_at(i) );
   2.238 +      for (int i = 0; i < length; i++) {
   2.239 +        dump_float(writer, array->float_at(i));
   2.240        }
   2.241        break;
   2.242      }
   2.243      case T_DOUBLE : {
   2.244 -      for (int i=0; i<array->length(); i++) {
   2.245 -        dump_double( writer, array->double_at(i) );
   2.246 +      for (int i = 0; i < length; i++) {
   2.247 +        dump_double(writer, array->double_at(i));
   2.248        }
   2.249        break;
   2.250      }
   2.251 @@ -1362,8 +1449,6 @@
   2.252    JavaThread*           _oome_thread;
   2.253    Method*               _oome_constructor;
   2.254    bool _gc_before_heap_dump;
   2.255 -  bool _is_segmented_dump;
   2.256 -  jlong _dump_start;
   2.257    GrowableArray<Klass*>* _klass_map;
   2.258    ThreadStackTrace** _stack_traces;
   2.259    int _num_threads;
   2.260 @@ -1382,11 +1467,6 @@
   2.261    void clear_global_dumper() { _global_dumper = NULL; }
   2.262    void clear_global_writer() { _global_writer = NULL; }
   2.263  
   2.264 -  bool is_segmented_dump() const                { return _is_segmented_dump; }
   2.265 -  void set_segmented_dump()                     { _is_segmented_dump = true; }
   2.266 -  jlong dump_start() const                      { return _dump_start; }
   2.267 -  void set_dump_start(jlong pos);
   2.268 -
   2.269    bool skip_operation() const;
   2.270  
   2.271    // writes a HPROF_LOAD_CLASS record
   2.272 @@ -1411,16 +1491,6 @@
   2.273    // HPROF_TRACE and HPROF_FRAME records
   2.274    void dump_stack_traces();
   2.275  
   2.276 -  // writes a HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT record
   2.277 -  void write_dump_header();
   2.278 -
   2.279 -  // fixes up the length of the current dump record
   2.280 -  void write_current_dump_record_length();
   2.281 -
   2.282 -  // fixes up the current dump record )and writes HPROF_HEAP_DUMP_END
   2.283 -  // record in the case of a segmented heap dump)
   2.284 -  void end_of_dump();
   2.285 -
   2.286   public:
   2.287    VM_HeapDumper(DumpWriter* writer, bool gc_before_heap_dump, bool oome) :
   2.288      VM_GC_Operation(0 /* total collections,      dummy, ignored */,
   2.289 @@ -1429,8 +1499,6 @@
   2.290                      gc_before_heap_dump) {
   2.291      _local_writer = writer;
   2.292      _gc_before_heap_dump = gc_before_heap_dump;
   2.293 -    _is_segmented_dump = false;
   2.294 -    _dump_start = (jlong)-1;
   2.295      _klass_map = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<Klass*>(INITIAL_CLASS_COUNT, true);
   2.296      _stack_traces = NULL;
   2.297      _num_threads = 0;
   2.298 @@ -1470,35 +1538,23 @@
   2.299    return false;
   2.300  }
   2.301  
   2.302 -// sets the dump starting position
   2.303 -void VM_HeapDumper::set_dump_start(jlong pos) {
   2.304 -  _dump_start = pos;
   2.305 -}
   2.306 -
   2.307 - // writes a HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT record
   2.308 -void VM_HeapDumper::write_dump_header() {
   2.309 -  if (writer()->is_open()) {
   2.310 -    if (is_segmented_dump()) {
   2.311 -      writer()->write_u1(HPROF_HEAP_DUMP_SEGMENT);
   2.312 -    } else {
   2.313 -      writer()->write_u1(HPROF_HEAP_DUMP);
   2.314 -    }
   2.315 -    writer()->write_u4(0); // current ticks
   2.316 + // writes a HPROF_HEAP_DUMP_SEGMENT record
   2.317 +void DumperSupport::write_dump_header(DumpWriter* writer) {
   2.318 +  if (writer->is_open()) {
   2.319 +    writer->write_u1(HPROF_HEAP_DUMP_SEGMENT);
   2.320 +    writer->write_u4(0); // current ticks
   2.321  
   2.322      // record the starting position for the dump (its length will be fixed up later)
   2.323 -    set_dump_start(writer()->current_offset());
   2.324 -    writer()->write_u4(0);
   2.325 +    writer->set_dump_start(writer->current_offset());
   2.326 +    writer->write_u4(0);
   2.327    }
   2.328  }
   2.329  
   2.330  // fixes up the length of the current dump record
   2.331 -void VM_HeapDumper::write_current_dump_record_length() {
   2.332 -  if (writer()->is_open()) {
   2.333 -    assert(dump_start() >= 0, "no dump start recorded");
   2.334 -
   2.335 -    // calculate the size of the dump record
   2.336 -    julong dump_end = writer()->current_offset();
   2.337 -    julong dump_len = (dump_end - dump_start() - 4);
   2.338 +void DumperSupport::write_current_dump_record_length(DumpWriter* writer) {
   2.339 +  if (writer->is_open()) {
   2.340 +    julong dump_end = writer->bytes_written() + writer->bytes_unwritten();
   2.341 +    julong dump_len = writer->current_record_length();
   2.342  
   2.343      // record length must fit in a u4
   2.344      if (dump_len > max_juint) {
   2.345 @@ -1506,17 +1562,18 @@
   2.346      }
   2.347  
   2.348      // seek to the dump start and fix-up the length
   2.349 -    writer()->seek_to_offset(dump_start());
   2.350 -    writer()->write_u4((u4)dump_len);
   2.351 +    assert(writer->dump_start() >= 0, "no dump start recorded");
   2.352 +    writer->seek_to_offset(writer->dump_start());
   2.353 +    writer->write_u4((u4)dump_len);
   2.354  
   2.355      // adjust the total size written to keep the bytes written correct.
   2.356 -    writer()->adjust_bytes_written(-((jlong) sizeof(u4)));
   2.357 +    writer->adjust_bytes_written(-((jlong) sizeof(u4)));
   2.358  
   2.359      // seek to dump end so we can continue
   2.360 -    writer()->seek_to_offset(dump_end);
   2.361 +    writer->seek_to_offset(dump_end);
   2.362  
   2.363      // no current dump record
   2.364 -    set_dump_start((jlong)-1);
   2.365 +    writer->set_dump_start((jlong)-1);
   2.366    }
   2.367  }
   2.368  
   2.369 @@ -1524,33 +1581,23 @@
   2.370  // new segment.
   2.371  void VM_HeapDumper::check_segment_length() {
   2.372    if (writer()->is_open()) {
   2.373 -    if (is_segmented_dump()) {
   2.374 -      // don't use current_offset that would be too expensive on a per record basis
   2.375 -      julong dump_end = writer()->bytes_written() + writer()->bytes_unwritten();
   2.376 -      assert(dump_end == (julong)writer()->current_offset(), "checking");
   2.377 -      julong dump_len = (dump_end - dump_start() - 4);
   2.378 -      assert(dump_len <= max_juint, "bad dump length");
   2.379 +    julong dump_len = writer()->current_record_length();
   2.380  
   2.381 -      if (dump_len > HeapDumpSegmentSize) {
   2.382 -        write_current_dump_record_length();
   2.383 -        write_dump_header();
   2.384 -      }
   2.385 +    if (dump_len > 2UL*G) {
   2.386 +      DumperSupport::write_current_dump_record_length(writer());
   2.387 +      DumperSupport::write_dump_header(writer());
   2.388      }
   2.389    }
   2.390  }
   2.391  
   2.392 -// fixes up the current dump record )and writes HPROF_HEAP_DUMP_END
   2.393 -// record in the case of a segmented heap dump)
   2.394 -void VM_HeapDumper::end_of_dump() {
   2.395 -  if (writer()->is_open()) {
   2.396 -    write_current_dump_record_length();
   2.397 +// fixes up the current dump record and writes HPROF_HEAP_DUMP_END record
   2.398 +void DumperSupport::end_of_dump(DumpWriter* writer) {
   2.399 +  if (writer->is_open()) {
   2.400 +    write_current_dump_record_length(writer);
   2.401  
   2.402 -    // for segmented dump we write the end record
   2.403 -    if (is_segmented_dump()) {
   2.404 -      writer()->write_u1(HPROF_HEAP_DUMP_END);
   2.405 -      writer()->write_u4(0);
   2.406 -      writer()->write_u4(0);
   2.407 -    }
   2.408 +    writer->write_u1(HPROF_HEAP_DUMP_END);
   2.409 +    writer->write_u4(0);
   2.410 +    writer->write_u4(0);
   2.411    }
   2.412  }
   2.413  
   2.414 @@ -1716,16 +1763,17 @@
   2.415  //  [HPROF_LOAD_CLASS]*
   2.416  //  [[HPROF_FRAME]*|HPROF_TRACE]*
   2.417  //  [HPROF_GC_CLASS_DUMP]*
   2.418 -//  HPROF_HEAP_DUMP
   2.419 +//  [HPROF_HEAP_DUMP_SEGMENT]*
   2.420 +//  HPROF_HEAP_DUMP_END
   2.421  //
   2.422  // The HPROF_TRACE records represent the stack traces where the heap dump
   2.423  // is generated and a "dummy trace" record which does not include
   2.424  // any frames. The dummy trace record is used to be referenced as the
   2.425  // unknown object alloc site.
   2.426  //
   2.427 -// The HPROF_HEAP_DUMP record has a length following by sub-records. To allow
   2.428 -// the heap dump be generated in a single pass we remember the position of
   2.429 -// the dump length and fix it up after all sub-records have been written.
   2.430 +// Each HPROF_HEAP_DUMP_SEGMENT record has a length followed by sub-records.
   2.431 +// To allow the heap dump be generated in a single pass we remember the position
   2.432 +// of the dump length and fix it up after all sub-records have been written.
   2.433  // To generate the sub-records we iterate over the heap, writing
   2.434  // HPROF_GC_INSTANCE_DUMP, HPROF_GC_OBJ_ARRAY_DUMP, and HPROF_GC_PRIM_ARRAY_DUMP
   2.435  // records as we go. Once that is done we write records for some of the GC
   2.436 @@ -1752,15 +1800,9 @@
   2.437    set_global_dumper();
   2.438    set_global_writer();
   2.439  
   2.440 -  // Write the file header - use 1.0.2 for large heaps, otherwise 1.0.1
   2.441 +  // Write the file header - we always use 1.0.2
   2.442    size_t used = ch->used();
   2.443 -  const char* header;
   2.444 -  if (used > (size_t)SegmentedHeapDumpThreshold) {
   2.445 -    set_segmented_dump();
   2.446 -    header = "JAVA PROFILE 1.0.2";
   2.447 -  } else {
   2.448 -    header = "JAVA PROFILE 1.0.1";
   2.449 -  }
   2.450 +  const char* header = "JAVA PROFILE 1.0.2";
   2.451  
   2.452    // header is few bytes long - no chance to overflow int
   2.453    writer()->write_raw((void*)header, (int)strlen(header));
   2.454 @@ -1780,8 +1822,8 @@
   2.455    // this must be called after _klass_map is built when iterating the classes above.
   2.456    dump_stack_traces();
   2.457  
   2.458 -  // write HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT
   2.459 -  write_dump_header();
   2.460 +  // write HPROF_HEAP_DUMP_SEGMENT
   2.461 +  DumperSupport::write_dump_header(writer());
   2.462  
   2.463    // Writes HPROF_GC_CLASS_DUMP records
   2.464    ClassLoaderDataGraph::classes_do(&do_class_dump);
   2.465 @@ -1789,9 +1831,9 @@
   2.466    check_segment_length();
   2.467  
   2.468    // writes HPROF_GC_INSTANCE_DUMP records.
   2.469 -  // After each sub-record is written check_segment_length will be invoked. When
   2.470 -  // generated a segmented heap dump this allows us to check if the current
   2.471 -  // segment exceeds a threshold and if so, then a new segment is started.
   2.472 +  // After each sub-record is written check_segment_length will be invoked
   2.473 +  // to check if the current segment exceeds a threshold. If so, a new
   2.474 +  // segment is started.
   2.475    // The HPROF_GC_CLASS_DUMP and HPROF_GC_INSTANCE_DUMP are the vast bulk
   2.476    // of the heap dump.
   2.477    HeapObjectDumper obj_dumper(this, writer());
   2.478 @@ -1817,9 +1859,8 @@
   2.479    StickyClassDumper class_dumper(writer());
   2.480    SystemDictionary::always_strong_classes_do(&class_dumper);
   2.481  
   2.482 -  // fixes up the length of the dump record. In the case of a segmented
   2.483 -  // heap then the HPROF_HEAP_DUMP_END record is also written.
   2.484 -  end_of_dump();
   2.485 +  // fixes up the length of the dump record and writes the HPROF_HEAP_DUMP_END record.
   2.486 +  DumperSupport::end_of_dump(writer());
   2.487  
   2.488    // Now we clear the global variables, so that a future dumper might run.
   2.489    clear_global_dumper();

mercurial