src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp
changeset 50113 caf115bb98ad
child 55571 49102ba8cf14
child 57870 00860d9caf4d
child 58678 9cf78a70fa4f
equal deleted inserted replaced
50112:7a2a740815b7 50113:caf115bb98ad
       
     1 /*
       
     2  * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  *
       
    23  */
       
    24 
       
    25 #include "precompiled.hpp"
       
    26 #include "jfrfiles/jfrTypes.hpp"
       
    27 #include "jfr/leakprofiler/chains/edge.hpp"
       
    28 #include "jfr/leakprofiler/chains/edgeStore.hpp"
       
    29 #include "jfr/leakprofiler/chains/edgeUtils.hpp"
       
    30 #include "jfr/leakprofiler/checkpoint/objectSampleDescription.hpp"
       
    31 #include "jfr/leakprofiler/checkpoint/objectSampleWriter.hpp"
       
    32 #include "jfr/leakprofiler/checkpoint/rootResolver.hpp"
       
    33 #include "jfr/leakprofiler/sampling/objectSampler.hpp"
       
    34 #include "jfr/leakprofiler/utilities/rootType.hpp"
       
    35 #include "jfr/leakprofiler/utilities/unifiedOop.hpp"
       
    36 #include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp"
       
    37 #include "jfr/recorder/checkpoint/types/jfrTypeSetWriter.hpp"
       
    38 #include "oops/oop.inline.hpp"
       
    39 #include "oops/symbol.hpp"
       
    40 #include "utilities/growableArray.hpp"
       
    41 
       
    42 template <typename Data>
       
    43 class ObjectSampleAuxInfo : public ResourceObj {
       
    44  public:
       
    45   Data _data;
       
    46   traceid _id;
       
    47   ObjectSampleAuxInfo() : _data(), _id(0) {}
       
    48 };
       
    49 
       
    50 class ObjectSampleArrayData {
       
    51  public:
       
    52   int _array_size;
       
    53   int _array_index;
       
    54   ObjectSampleArrayData() : _array_size(0), _array_index(0) {}
       
    55 };
       
    56 
       
    57 class ObjectSampleFieldInfo : public ResourceObj {
       
    58  public:
       
    59   const Symbol* _field_name_symbol;
       
    60   jshort _field_modifiers;
       
    61   ObjectSampleFieldInfo() : _field_name_symbol(NULL), _field_modifiers(0) {}
       
    62 };
       
    63 
       
    64 class ObjectSampleRootDescriptionData {
       
    65  public:
       
    66   const Edge* _root_edge;
       
    67   const char* _description;
       
    68   OldObjectRoot::System _system;
       
    69   OldObjectRoot::Type _type;
       
    70   ObjectSampleRootDescriptionData() : _root_edge(NULL),
       
    71                                       _description(NULL),
       
    72                                       _system(OldObjectRoot::_system_undetermined),
       
    73                                       _type(OldObjectRoot::_type_undetermined) {}
       
    74 };
       
    75 
       
    76 class OldObjectSampleData {
       
    77  public:
       
    78   oop _object;
       
    79   traceid _reference_id;
       
    80 };
       
    81 
       
    82 class ReferenceData {
       
    83  public:
       
    84   traceid _field_info_id;
       
    85   traceid _array_info_id;
       
    86   traceid _old_object_sample_id;
       
    87   size_t  _skip;
       
    88 };
       
    89 
       
    90 static int initial_storage_size = 16;
       
    91 
       
    92 template <typename Data>
       
    93 class SampleSet : public ResourceObj {
       
    94  private:
       
    95   GrowableArray<Data>* _storage;
       
    96  public:
       
    97   SampleSet() : _storage(NULL) {}
       
    98 
       
    99   traceid store(Data data) {
       
   100     assert(data != NULL, "invariant");
       
   101     if (_storage == NULL) {
       
   102       _storage = new GrowableArray<Data>(initial_storage_size);
       
   103     }
       
   104     assert(_storage != NULL, "invariant");
       
   105     assert(_storage->find(data) == -1, "invariant");
       
   106     _storage->append(data);
       
   107     return data->_id;
       
   108   }
       
   109 
       
   110   size_t size() const {
       
   111     return _storage != NULL ? (size_t)_storage->length() : 0;
       
   112   }
       
   113 
       
   114   template <typename Functor>
       
   115   void iterate(Functor& functor) {
       
   116     if (_storage != NULL) {
       
   117       for (int i = 0; i < _storage->length(); ++i) {
       
   118         functor(_storage->at(i));
       
   119       }
       
   120     }
       
   121   }
       
   122 
       
   123   const GrowableArray<Data>& storage() const {
       
   124     return *_storage;
       
   125   }
       
   126 };
       
   127 
       
   128 typedef ObjectSampleAuxInfo<ObjectSampleArrayData> ObjectSampleArrayInfo;
       
   129 typedef ObjectSampleAuxInfo<ObjectSampleRootDescriptionData> ObjectSampleRootDescriptionInfo;
       
   130 typedef ObjectSampleAuxInfo<OldObjectSampleData> OldObjectSampleInfo;
       
   131 typedef ObjectSampleAuxInfo<ReferenceData> ReferenceInfo;
       
   132 
       
   133 class FieldTable : public ResourceObj {
       
   134   template <typename,
       
   135             typename,
       
   136             template<typename, typename> class,
       
   137             typename,
       
   138             size_t>
       
   139   friend class HashTableHost;
       
   140   typedef HashTableHost<const ObjectSampleFieldInfo*, traceid, Entry, FieldTable, 109> FieldInfoTable;
       
   141  public:
       
   142   typedef FieldInfoTable::HashEntry FieldInfoEntry;
       
   143 
       
   144  private:
       
   145   static traceid _field_id_counter;
       
   146   FieldInfoTable* _table;
       
   147 
       
   148   void assign_id(FieldInfoEntry* entry) {
       
   149     assert(entry != NULL, "invariant");
       
   150     entry->set_id(++_field_id_counter);
       
   151   }
       
   152 
       
   153   bool equals(const ObjectSampleFieldInfo* query, uintptr_t hash, const FieldInfoEntry* entry) {
       
   154     assert(hash == entry->hash(), "invariant");
       
   155     assert(query != NULL, "invariant");
       
   156     const ObjectSampleFieldInfo* stored = entry->literal();
       
   157     assert(stored != NULL, "invariant");
       
   158     assert(stored->_field_name_symbol->identity_hash() == query->_field_name_symbol->identity_hash(), "invariant");
       
   159     return stored->_field_modifiers == query->_field_modifiers;
       
   160   }
       
   161 
       
   162  public:
       
   163   FieldTable() : _table(new FieldInfoTable(this)) {}
       
   164   ~FieldTable() {
       
   165     assert(_table != NULL, "invariant");
       
   166     delete _table;
       
   167   }
       
   168 
       
   169   traceid store(const ObjectSampleFieldInfo* field_info) {
       
   170     assert(field_info != NULL, "invariant");
       
   171     const FieldInfoEntry& entry =_table->lookup_put(field_info,
       
   172                                                     field_info->_field_name_symbol->identity_hash());
       
   173     return entry.id();
       
   174   }
       
   175 
       
   176   size_t size() const {
       
   177     return _table->cardinality();
       
   178   }
       
   179 
       
   180   template <typename T>
       
   181   void iterate(T& functor) const {
       
   182     _table->iterate_entry<T>(functor);
       
   183   }
       
   184 };
       
   185 
       
   186 traceid FieldTable::_field_id_counter = 0;
       
   187 
       
   188 typedef SampleSet<const OldObjectSampleInfo*> SampleInfo;
       
   189 typedef SampleSet<const ReferenceInfo*> RefInfo;
       
   190 typedef SampleSet<const ObjectSampleArrayInfo*> ArrayInfo;
       
   191 typedef SampleSet<const ObjectSampleRootDescriptionInfo*> RootDescriptionInfo;
       
   192 
       
   193 static SampleInfo* sample_infos = NULL;
       
   194 static RefInfo* ref_infos = NULL;
       
   195 static ArrayInfo* array_infos = NULL;
       
   196 static FieldTable* field_infos = NULL;
       
   197 static RootDescriptionInfo* root_infos = NULL;
       
   198 
       
   199 int __write_sample_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* si) {
       
   200   assert(writer != NULL, "invariant");
       
   201   assert(si != NULL, "invariant");
       
   202   const OldObjectSampleInfo* const oosi = (const OldObjectSampleInfo*)si;
       
   203   oop object = oosi->_data._object;
       
   204   assert(object != NULL, "invariant");
       
   205   writer->write(oosi->_id);
       
   206   writer->write((u8)(const HeapWord*)object);
       
   207   writer->write(const_cast<const Klass*>(object->klass()));
       
   208   ObjectSampleDescription od(object);
       
   209   writer->write(od.description());
       
   210   writer->write(oosi->_data._reference_id);
       
   211   return 1;
       
   212 }
       
   213 
       
   214 typedef JfrArtifactWriterImplHost<const OldObjectSampleInfo*, __write_sample_info__> SampleWriterImpl;
       
   215 typedef JfrArtifactWriterHost<SampleWriterImpl, TYPE_OLDOBJECT> SampleWriter;
       
   216 
       
   217 static void write_sample_infos(JfrCheckpointWriter& writer) {
       
   218   if (sample_infos != NULL) {
       
   219     SampleWriter sw(&writer, NULL, false);
       
   220     sample_infos->iterate(sw);
       
   221   }
       
   222 }
       
   223 
       
   224 int __write_reference_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* ri) {
       
   225   assert(writer != NULL, "invariant");
       
   226   assert(ri != NULL, "invariant");
       
   227   const ReferenceInfo* const ref_info = (const ReferenceInfo*)ri;
       
   228   writer->write(ref_info->_id);
       
   229   writer->write(ref_info->_data._array_info_id);
       
   230   writer->write(ref_info->_data._field_info_id);
       
   231   writer->write(ref_info->_data._old_object_sample_id);
       
   232   writer->write<s4>((s4)ref_info->_data._skip);
       
   233   return 1;
       
   234 }
       
   235 
       
   236 typedef JfrArtifactWriterImplHost<const ReferenceInfo*, __write_reference_info__> ReferenceWriterImpl;
       
   237 typedef JfrArtifactWriterHost<ReferenceWriterImpl, TYPE_REFERENCE> ReferenceWriter;
       
   238 
       
   239 static void write_reference_infos(JfrCheckpointWriter& writer) {
       
   240   if (ref_infos != NULL) {
       
   241     ReferenceWriter rw(&writer, NULL, false);
       
   242     ref_infos->iterate(rw);
       
   243   }
       
   244 }
       
   245 
       
   246 int __write_array_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* ai) {
       
   247   assert(writer != NULL, "invariant");
       
   248   assert(ai != NULL, "invariant");
       
   249   const ObjectSampleArrayInfo* const osai = (const ObjectSampleArrayInfo*)ai;
       
   250   writer->write(osai->_id);
       
   251   writer->write(osai->_data._array_size);
       
   252   writer->write(osai->_data._array_index);
       
   253   return 1;
       
   254 }
       
   255 
       
   256 static traceid get_array_info_id(const Edge& edge, traceid id) {
       
   257   if (edge.is_root() || !EdgeUtils::is_array_element(edge)) {
       
   258     return 0;
       
   259   }
       
   260   if (array_infos == NULL) {
       
   261     array_infos = new ArrayInfo();
       
   262   }
       
   263   assert(array_infos != NULL, "invariant");
       
   264 
       
   265   ObjectSampleArrayInfo* const osai = new ObjectSampleArrayInfo();
       
   266   assert(osai != NULL, "invariant");
       
   267   osai->_id = id;
       
   268   osai->_data._array_size = EdgeUtils::array_size(edge);
       
   269   osai->_data._array_index = EdgeUtils::array_index(edge);
       
   270   return array_infos->store(osai);
       
   271 }
       
   272 
       
   273 typedef JfrArtifactWriterImplHost<const ObjectSampleArrayInfo*, __write_array_info__> ArrayWriterImpl;
       
   274 typedef JfrArtifactWriterHost<ArrayWriterImpl, TYPE_OLDOBJECTARRAY> ArrayWriter;
       
   275 
       
   276 static void write_array_infos(JfrCheckpointWriter& writer) {
       
   277   if (array_infos != NULL) {
       
   278     ArrayWriter aw(&writer, NULL, false);
       
   279     array_infos->iterate(aw);
       
   280   }
       
   281 }
       
   282 
       
   283 int __write_field_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* fi) {
       
   284   assert(writer != NULL, "invariant");
       
   285   assert(fi != NULL, "invariant");
       
   286   const FieldTable::FieldInfoEntry* field_info_entry = (const FieldTable::FieldInfoEntry*)fi;
       
   287   writer->write(field_info_entry->id());
       
   288   const ObjectSampleFieldInfo* const osfi = field_info_entry->literal();
       
   289   writer->write(osfi->_field_name_symbol->as_C_string());
       
   290   writer->write(osfi->_field_modifiers);
       
   291   return 1;
       
   292 }
       
   293 
       
   294 static traceid get_field_info_id(const Edge& edge) {
       
   295   if (edge.is_root()) {
       
   296     return 0;
       
   297   }
       
   298 
       
   299   assert(!EdgeUtils::is_array_element(edge), "invariant");
       
   300   const Symbol* const field_name_symbol = EdgeUtils::field_name_symbol(edge);
       
   301   if (field_name_symbol == NULL) {
       
   302     return 0;
       
   303   }
       
   304 
       
   305   if (field_infos == NULL) {
       
   306     field_infos = new FieldTable();
       
   307   }
       
   308   assert(field_infos != NULL, "invariant");
       
   309 
       
   310   ObjectSampleFieldInfo* const osfi = new ObjectSampleFieldInfo();
       
   311   assert(osfi != NULL, "invariant");
       
   312   osfi->_field_name_symbol = field_name_symbol;
       
   313   osfi->_field_modifiers = EdgeUtils::field_modifiers(edge);
       
   314   return field_infos->store(osfi);
       
   315 }
       
   316 
       
   317 typedef JfrArtifactWriterImplHost<const FieldTable::FieldInfoEntry*, __write_field_info__> FieldWriterImpl;
       
   318 typedef JfrArtifactWriterHost<FieldWriterImpl, TYPE_OLDOBJECTFIELD> FieldWriter;
       
   319 
       
   320 static void write_field_infos(JfrCheckpointWriter& writer) {
       
   321   if (field_infos != NULL) {
       
   322     FieldWriter fw(&writer, NULL, false);
       
   323     field_infos->iterate(fw);
       
   324   }
       
   325 }
       
   326 
       
   327 static const char* description(const ObjectSampleRootDescriptionInfo* osdi) {
       
   328   assert(osdi != NULL, "invariant");
       
   329 
       
   330   if (osdi->_data._description == NULL) {
       
   331     return NULL;
       
   332   }
       
   333 
       
   334   ObjectDescriptionBuilder description;
       
   335   if (osdi->_data._system == OldObjectRoot::_threads) {
       
   336     description.write_text("Thread Name: ");
       
   337   }
       
   338   description.write_text(osdi->_data._description);
       
   339   return description.description();
       
   340 }
       
   341 
       
   342 int __write_root_description_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* di) {
       
   343   assert(writer != NULL, "invariant");
       
   344   assert(di != NULL, "invariant");
       
   345   const ObjectSampleRootDescriptionInfo* const osdi = (const ObjectSampleRootDescriptionInfo*)di;
       
   346   writer->write(osdi->_id);
       
   347   writer->write(description(osdi));
       
   348   writer->write<u8>(osdi->_data._system);
       
   349   writer->write<u8>(osdi->_data._type);
       
   350   return 1;
       
   351 }
       
   352 
       
   353 static traceid get_root_description_info_id(const Edge& edge, traceid id) {
       
   354   assert(edge.is_root(), "invariant");
       
   355   if (EdgeUtils::is_leak_edge(edge)) {
       
   356     return 0;
       
   357   }
       
   358 
       
   359   if (root_infos == NULL) {
       
   360     root_infos = new RootDescriptionInfo();
       
   361   }
       
   362   assert(root_infos != NULL, "invariant");
       
   363   ObjectSampleRootDescriptionInfo* const oodi = new ObjectSampleRootDescriptionInfo();
       
   364   oodi->_id = id;
       
   365   oodi->_data._root_edge = &edge;
       
   366   return root_infos->store(oodi);
       
   367 }
       
   368 
       
   369 typedef JfrArtifactWriterImplHost<const ObjectSampleRootDescriptionInfo*, __write_root_description_info__> RootDescriptionWriterImpl;
       
   370 typedef JfrArtifactWriterHost<RootDescriptionWriterImpl, TYPE_OLDOBJECTGCROOT> RootDescriptionWriter;
       
   371 
       
   372 
       
   373 int _edge_reference_compare_(uintptr_t lhs, uintptr_t rhs) {
       
   374   return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0;
       
   375 }
       
   376 
       
   377 int _root_desc_compare_(const ObjectSampleRootDescriptionInfo*const & lhs, const ObjectSampleRootDescriptionInfo* const& rhs) {
       
   378   const uintptr_t lhs_ref = (uintptr_t)lhs->_data._root_edge->reference();
       
   379   const uintptr_t rhs_ref = (uintptr_t)rhs->_data._root_edge->reference();
       
   380   return _edge_reference_compare_(lhs_ref, rhs_ref);
       
   381 }
       
   382 
       
   383 static int find_sorted(const RootCallbackInfo& callback_info,
       
   384                        const GrowableArray<const ObjectSampleRootDescriptionInfo*>* arr,
       
   385                        int length,
       
   386                        bool& found) {
       
   387   assert(arr != NULL, "invariant");
       
   388   assert(length >= 0, "invariant");
       
   389   assert(length <= arr->length(), "invariant");
       
   390 
       
   391   found = false;
       
   392   int min = 0;
       
   393   int max = length;
       
   394   while (max >= min) {
       
   395     const int mid = (int)(((uint)max + min) / 2);
       
   396     int diff = _edge_reference_compare_((uintptr_t)callback_info._high,
       
   397                                         (uintptr_t)arr->at(mid)->_data._root_edge->reference());
       
   398     if (diff > 0) {
       
   399       min = mid + 1;
       
   400     } else if (diff < 0) {
       
   401       max = mid - 1;
       
   402     } else {
       
   403       found = true;
       
   404       return mid;
       
   405     }
       
   406   }
       
   407   return min;
       
   408 }
       
   409 
       
   410 class RootResolutionSet : public ResourceObj, public RootCallback {
       
   411  private:
       
   412   GrowableArray<const ObjectSampleRootDescriptionInfo*>* _unresolved_roots;
       
   413 
       
   414   const uintptr_t high() const {
       
   415     return (uintptr_t)_unresolved_roots->last()->_data._root_edge->reference();
       
   416   }
       
   417 
       
   418   const uintptr_t low() const {
       
   419     return (uintptr_t)_unresolved_roots->first()->_data._root_edge->reference();
       
   420   }
       
   421 
       
   422   bool in_set_address_range(const RootCallbackInfo& callback_info) const {
       
   423     assert(callback_info._low == NULL, "invariant");
       
   424     const uintptr_t addr = (uintptr_t)callback_info._high;
       
   425     return low() <= addr && high() >= addr;
       
   426   }
       
   427 
       
   428   int compare_to_range(const RootCallbackInfo& callback_info) const {
       
   429     assert(callback_info._high != NULL, "invariant");
       
   430     assert(callback_info._low != NULL, "invariant");
       
   431 
       
   432     for (int i = 0; i < _unresolved_roots->length(); ++i) {
       
   433       const uintptr_t ref_addr = (uintptr_t)_unresolved_roots->at(i)->_data._root_edge->reference();
       
   434       if ((uintptr_t)callback_info._low <= ref_addr && (uintptr_t)callback_info._high >= ref_addr) {
       
   435         return i;
       
   436       }
       
   437     }
       
   438     return -1;
       
   439   }
       
   440 
       
   441   int exact(const RootCallbackInfo& callback_info) const {
       
   442     assert(callback_info._high != NULL, "invariant");
       
   443     assert(in_set_address_range(callback_info), "invariant");
       
   444 
       
   445     bool found;
       
   446     const int idx = find_sorted(callback_info, _unresolved_roots, _unresolved_roots->length(), found);
       
   447     return found ? idx : -1;
       
   448   }
       
   449 
       
   450   bool resolve_root(const RootCallbackInfo& callback_info, int idx) const {
       
   451     assert(idx >= 0, "invariant");
       
   452     assert(idx < _unresolved_roots->length(), "invariant");
       
   453 
       
   454     ObjectSampleRootDescriptionInfo* const desc =
       
   455       const_cast<ObjectSampleRootDescriptionInfo*>(_unresolved_roots->at(idx));
       
   456     assert(desc != NULL, "invariant");
       
   457     assert((uintptr_t)callback_info._high == (uintptr_t)desc->_data._root_edge->reference(), "invariant");
       
   458 
       
   459     desc->_data._system = callback_info._system;
       
   460     desc->_data._type = callback_info._type;
       
   461 
       
   462     if (callback_info._system == OldObjectRoot::_threads) {
       
   463       const JavaThread* jt = (const JavaThread*)callback_info._context;
       
   464       assert(jt != NULL, "invariant");
       
   465       desc->_data._description = jt->name();
       
   466     }
       
   467 
       
   468     _unresolved_roots->remove_at(idx);
       
   469     return _unresolved_roots->is_empty();
       
   470   }
       
   471 
       
   472  public:
       
   473   RootResolutionSet(RootDescriptionInfo* info) : _unresolved_roots(NULL) {
       
   474     assert(info != NULL, "invariant");
       
   475     // construct a sorted copy
       
   476     const GrowableArray<const ObjectSampleRootDescriptionInfo*>& info_storage = info->storage();
       
   477     const int length = info_storage.length();
       
   478     _unresolved_roots = new GrowableArray<const ObjectSampleRootDescriptionInfo*>(length);
       
   479     assert(_unresolved_roots != NULL, "invariant");
       
   480 
       
   481     for (int i = 0; i < length; ++i) {
       
   482       _unresolved_roots->insert_sorted<_root_desc_compare_>(info_storage.at(i));
       
   483     }
       
   484   }
       
   485 
       
   486   bool process(const RootCallbackInfo& callback_info) {
       
   487     if (NULL == callback_info._low) {
       
   488       if (in_set_address_range(callback_info)) {
       
   489         const int idx = exact(callback_info);
       
   490         return idx == -1 ? false : resolve_root(callback_info, idx);
       
   491       }
       
   492       return false;
       
   493     }
       
   494     assert(callback_info._low != NULL, "invariant");
       
   495     const int idx = compare_to_range(callback_info);
       
   496     return idx == -1 ? false : resolve_root(callback_info, idx);
       
   497   }
       
   498 
       
   499   int entries() const {
       
   500     return _unresolved_roots->length();
       
   501   }
       
   502 
       
   503   const void* at(int idx) const {
       
   504     assert(idx >= 0, "invariant");
       
   505     assert(idx < _unresolved_roots->length(), "invariant");
       
   506     return _unresolved_roots->at(idx)->_data._root_edge->reference();
       
   507   }
       
   508 };
       
   509 
       
   510 static void write_root_descriptors(JfrCheckpointWriter& writer) {
       
   511   if (root_infos != NULL) {
       
   512     // resolve roots
       
   513     RootResolutionSet rrs(root_infos);
       
   514     RootResolver::resolve(rrs);
       
   515     // write roots
       
   516     RootDescriptionWriter rw(&writer, NULL, false);
       
   517     root_infos->iterate(rw);
       
   518   }
       
   519 }
       
   520 
       
   521 static void add_old_object_sample_info(const Edge* current, traceid id) {
       
   522   assert(current != NULL, "invariant");
       
   523   if (sample_infos == NULL) {
       
   524     sample_infos = new SampleInfo();
       
   525   }
       
   526   assert(sample_infos != NULL, "invariant");
       
   527   OldObjectSampleInfo* const oosi = new OldObjectSampleInfo();
       
   528   assert(oosi != NULL, "invariant");
       
   529   oosi->_id = id;
       
   530   oosi->_data._object = current->pointee();
       
   531   oosi->_data._reference_id = current->is_root() ? (traceid)0 : id;
       
   532   sample_infos->store(oosi);
       
   533 }
       
   534 
       
   535 static void add_reference_info(const RoutableEdge* current, traceid id, traceid parent_id) {
       
   536   assert(current != NULL, "invariant");
       
   537   if (ref_infos == NULL) {
       
   538     ref_infos = new RefInfo();
       
   539   }
       
   540 
       
   541   assert(ref_infos != NULL, "invariant");
       
   542   ReferenceInfo* const ri = new ReferenceInfo();
       
   543   assert(ri != NULL, "invariant");
       
   544 
       
   545   ri->_id = id;
       
   546   ri->_data._array_info_id =  !current->is_skip_edge() ? get_array_info_id(*current, id) : 0;
       
   547   ri->_data._field_info_id = ri->_data._array_info_id == 0 && !current->is_skip_edge() ?
       
   548                                get_field_info_id(*current) : (traceid)0;
       
   549   ri->_data._old_object_sample_id = parent_id;
       
   550   ri->_data._skip = current->skip_length();
       
   551   ref_infos->store(ri);
       
   552 }
       
   553 
       
   554 static traceid add_root_info(const Edge* root, traceid id) {
       
   555   assert(root != NULL, "invariant");
       
   556   assert(root->is_root(), "invariant");
       
   557   return get_root_description_info_id(*root, id);
       
   558 }
       
   559 
       
   560 void ObjectSampleWriter::write(const RoutableEdge* edge) {
       
   561   assert(edge != NULL, "invariant");
       
   562   const traceid id = _store->get_id(edge);
       
   563   add_old_object_sample_info(edge, id);
       
   564   const RoutableEdge* parent = edge->logical_parent();
       
   565   if (parent != NULL) {
       
   566     add_reference_info(edge, id, _store->get_id(parent));
       
   567   } else {
       
   568     assert(edge->is_root(), "invariant");
       
   569     add_root_info(edge, id);
       
   570   }
       
   571 }
       
   572 
       
   573 ObjectSampleWriter::ObjectSampleWriter(JfrCheckpointWriter& writer, const EdgeStore* store) :
       
   574   _writer(writer),
       
   575   _store(store) {
       
   576   assert(store != NULL, "invariant");
       
   577   assert(store->number_of_entries() > 0, "invariant");
       
   578   sample_infos = NULL;
       
   579   ref_infos = NULL;
       
   580   array_infos = NULL;
       
   581   field_infos = NULL;
       
   582   root_infos = NULL;
       
   583 }
       
   584 
       
   585 ObjectSampleWriter::~ObjectSampleWriter() {
       
   586   write_sample_infos(_writer);
       
   587   write_reference_infos(_writer);
       
   588   write_array_infos(_writer);
       
   589   write_field_infos(_writer);
       
   590   write_root_descriptors(_writer);
       
   591 }
       
   592 
       
   593 void ObjectSampleWriter::write_chain(const RoutableEdge& edge) {
       
   594   assert(EdgeUtils::is_leak_edge(edge), "invariant");
       
   595   if (edge.processed()) {
       
   596     return;
       
   597   }
       
   598   EdgeUtils::collapse_chain(edge);
       
   599   const RoutableEdge* current = &edge;
       
   600   while (current != NULL) {
       
   601     if (current->processed()) {
       
   602       return;
       
   603     }
       
   604     write(current);
       
   605     current->set_processed();
       
   606     current = current->logical_parent();
       
   607   }
       
   608 }
       
   609 
       
   610 bool ObjectSampleWriter::operator()(const RoutableEdge& edge) {
       
   611   if (EdgeUtils::is_leak_edge(edge)) {
       
   612     write_chain(edge);
       
   613   }
       
   614   return true;
       
   615 }