1 /*
2  * Copyright (c) 2014, 2020, 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/metadata/jfrSerializer.hpp"
37 #include "jfr/writers/jfrTypeWriterHost.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;
ObjectSampleAuxInfo()47   ObjectSampleAuxInfo() : _data(), _id(0) {}
48 };
49 
50 class ObjectSampleArrayData {
51  public:
52   int _array_size;
53   int _array_index;
ObjectSampleArrayData()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;
ObjectSampleFieldInfo()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;
ObjectSampleRootDescriptionData()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:
SampleSet()97   SampleSet() : _storage(NULL) {}
98 
store(Data data)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 
size() const110   size_t size() const {
111     return _storage != NULL ? (size_t)_storage->length() : 0;
112   }
113 
114   template <typename Functor>
iterate(Functor & 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 
storage() const123   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, JfrHashtableEntry, FieldTable, 109> FieldInfoTable;
141  public:
142   typedef FieldInfoTable::HashEntry FieldInfoEntry;
143 
144  private:
145   static traceid _field_id_counter;
146   FieldInfoTable* _table;
147   const ObjectSampleFieldInfo* _lookup;
148 
on_link(FieldInfoEntry * entry)149   void on_link(FieldInfoEntry* entry) {
150     assert(entry != NULL, "invariant");
151     entry->set_id(++_field_id_counter);
152   }
153 
on_equals(uintptr_t hash,const FieldInfoEntry * entry)154   bool on_equals(uintptr_t hash, const FieldInfoEntry* entry) {
155     assert(hash == entry->hash(), "invariant");
156     assert(_lookup != NULL, "invariant");
157     return entry->literal()->_field_modifiers == _lookup->_field_modifiers;
158   }
159 
on_unlink(FieldInfoEntry * entry)160   void on_unlink(FieldInfoEntry* entry) {
161     assert(entry != NULL, "invariant");
162     // nothing
163   }
164 
165  public:
FieldTable()166   FieldTable() : _table(new FieldInfoTable(this)), _lookup(NULL) {}
~FieldTable()167   ~FieldTable() {
168     assert(_table != NULL, "invariant");
169     delete _table;
170   }
171 
store(const ObjectSampleFieldInfo * field_info)172   traceid store(const ObjectSampleFieldInfo* field_info) {
173     assert(field_info != NULL, "invariant");
174     _lookup = field_info;
175     const FieldInfoEntry& entry = _table->lookup_put(field_info->_field_name_symbol->identity_hash(), field_info);
176     return entry.id();
177   }
178 
size() const179   size_t size() const {
180     return _table->cardinality();
181   }
182 
183   template <typename T>
iterate(T & functor) const184   void iterate(T& functor) const {
185     _table->iterate_entry<T>(functor);
186   }
187 };
188 
189 traceid FieldTable::_field_id_counter = 0;
190 
191 typedef SampleSet<const OldObjectSampleInfo*> SampleInfo;
192 typedef SampleSet<const ReferenceInfo*> RefInfo;
193 typedef SampleSet<const ObjectSampleArrayInfo*> ArrayInfo;
194 typedef SampleSet<const ObjectSampleRootDescriptionInfo*> RootDescriptionInfo;
195 
196 static SampleInfo* sample_infos = NULL;
197 static RefInfo* ref_infos = NULL;
198 static ArrayInfo* array_infos = NULL;
199 static FieldTable* field_infos = NULL;
200 static RootDescriptionInfo* root_infos = NULL;
201 
__write_sample_info__(JfrCheckpointWriter * writer,const void * si)202 int __write_sample_info__(JfrCheckpointWriter* writer, const void* si) {
203   assert(writer != NULL, "invariant");
204   assert(si != NULL, "invariant");
205   const OldObjectSampleInfo* const oosi = (const OldObjectSampleInfo*)si;
206   oop object = oosi->_data._object;
207   assert(object != NULL, "invariant");
208   writer->write(oosi->_id);
209   writer->write((u8)(const HeapWord*)object);
210   writer->write(const_cast<const Klass*>(object->klass()));
211   ObjectSampleDescription od(object);
212   writer->write(od.description());
213   writer->write(oosi->_data._reference_id);
214   return 1;
215 }
216 
217 typedef JfrTypeWriterImplHost<const OldObjectSampleInfo*, __write_sample_info__> SampleWriterImpl;
218 typedef JfrTypeWriterHost<SampleWriterImpl, TYPE_OLDOBJECT> SampleWriter;
219 
write_sample_infos(JfrCheckpointWriter & writer)220 static void write_sample_infos(JfrCheckpointWriter& writer) {
221   if (sample_infos != NULL) {
222     SampleWriter sw(&writer);
223     sample_infos->iterate(sw);
224   }
225 }
226 
__write_reference_info__(JfrCheckpointWriter * writer,const void * ri)227 int __write_reference_info__(JfrCheckpointWriter* writer, const void* ri) {
228   assert(writer != NULL, "invariant");
229   assert(ri != NULL, "invariant");
230   const ReferenceInfo* const ref_info = (const ReferenceInfo*)ri;
231   writer->write(ref_info->_id);
232   writer->write(ref_info->_data._array_info_id);
233   writer->write(ref_info->_data._field_info_id);
234   writer->write(ref_info->_data._old_object_sample_id);
235   writer->write<s4>((s4)ref_info->_data._skip);
236   return 1;
237 }
238 
239 typedef JfrTypeWriterImplHost<const ReferenceInfo*, __write_reference_info__> ReferenceWriterImpl;
240 typedef JfrTypeWriterHost<ReferenceWriterImpl, TYPE_REFERENCE> ReferenceWriter;
241 
write_reference_infos(JfrCheckpointWriter & writer)242 static void write_reference_infos(JfrCheckpointWriter& writer) {
243   if (ref_infos != NULL) {
244     ReferenceWriter rw(&writer);
245     ref_infos->iterate(rw);
246   }
247 }
248 
__write_array_info__(JfrCheckpointWriter * writer,const void * ai)249 int __write_array_info__(JfrCheckpointWriter* writer, const void* ai) {
250   assert(writer != NULL, "invariant");
251   assert(ai != NULL, "invariant");
252   const ObjectSampleArrayInfo* const osai = (const ObjectSampleArrayInfo*)ai;
253   writer->write(osai->_id);
254   writer->write(osai->_data._array_size);
255   writer->write(osai->_data._array_index);
256   return 1;
257 }
258 
get_array_info_id(const Edge & edge,traceid id)259 static traceid get_array_info_id(const Edge& edge, traceid id) {
260   if (edge.is_root() || !EdgeUtils::is_array_element(edge)) {
261     return 0;
262   }
263   if (array_infos == NULL) {
264     array_infos = new ArrayInfo();
265   }
266   assert(array_infos != NULL, "invariant");
267 
268   ObjectSampleArrayInfo* const osai = new ObjectSampleArrayInfo();
269   assert(osai != NULL, "invariant");
270   osai->_id = id;
271   osai->_data._array_size = EdgeUtils::array_size(edge);
272   osai->_data._array_index = EdgeUtils::array_index(edge);
273   return array_infos->store(osai);
274 }
275 
276 typedef JfrTypeWriterImplHost<const ObjectSampleArrayInfo*, __write_array_info__> ArrayWriterImpl;
277 typedef JfrTypeWriterHost<ArrayWriterImpl, TYPE_OLDOBJECTARRAY> ArrayWriter;
278 
write_array_infos(JfrCheckpointWriter & writer)279 static void write_array_infos(JfrCheckpointWriter& writer) {
280   if (array_infos != NULL) {
281     ArrayWriter aw(&writer);
282     array_infos->iterate(aw);
283   }
284 }
285 
__write_field_info__(JfrCheckpointWriter * writer,const void * fi)286 int __write_field_info__(JfrCheckpointWriter* writer, const void* fi) {
287   assert(writer != NULL, "invariant");
288   assert(fi != NULL, "invariant");
289   const FieldTable::FieldInfoEntry* field_info_entry = (const FieldTable::FieldInfoEntry*)fi;
290   writer->write(field_info_entry->id());
291   const ObjectSampleFieldInfo* const osfi = field_info_entry->literal();
292   writer->write(osfi->_field_name_symbol->as_C_string());
293   writer->write(osfi->_field_modifiers);
294   return 1;
295 }
296 
get_field_info_id(const Edge & edge)297 static traceid get_field_info_id(const Edge& edge) {
298   if (edge.is_root()) {
299     return 0;
300   }
301 
302   assert(!EdgeUtils::is_array_element(edge), "invariant");
303   jshort field_modifiers = 0;
304   const Symbol* const field_name_symbol = EdgeUtils::field_name(edge, &field_modifiers);
305   if (field_name_symbol == NULL) {
306     return 0;
307   }
308   if (field_infos == NULL) {
309     field_infos = new FieldTable();
310   }
311   assert(field_infos != NULL, "invariant");
312   ObjectSampleFieldInfo* const osfi = new ObjectSampleFieldInfo();
313   assert(osfi != NULL, "invariant");
314   osfi->_field_name_symbol = field_name_symbol;
315   osfi->_field_modifiers = field_modifiers;
316   return field_infos->store(osfi);
317 }
318 
319 typedef JfrTypeWriterImplHost<const FieldTable::FieldInfoEntry*, __write_field_info__> FieldWriterImpl;
320 typedef JfrTypeWriterHost<FieldWriterImpl, TYPE_OLDOBJECTFIELD> FieldWriter;
321 
write_field_infos(JfrCheckpointWriter & writer)322 static void write_field_infos(JfrCheckpointWriter& writer) {
323   if (field_infos != NULL) {
324     FieldWriter fw(&writer);
325     field_infos->iterate(fw);
326   }
327 }
328 
description(const ObjectSampleRootDescriptionInfo * osdi)329 static const char* description(const ObjectSampleRootDescriptionInfo* osdi) {
330   assert(osdi != NULL, "invariant");
331 
332   if (osdi->_data._description == NULL) {
333     return NULL;
334   }
335 
336   ObjectDescriptionBuilder description;
337   if (osdi->_data._system == OldObjectRoot::_threads) {
338     description.write_text("Thread Name: ");
339   }
340   description.write_text(osdi->_data._description);
341   return description.description();
342 }
343 
__write_root_description_info__(JfrCheckpointWriter * writer,const void * di)344 int __write_root_description_info__(JfrCheckpointWriter* writer, const void* di) {
345   assert(writer != NULL, "invariant");
346   assert(di != NULL, "invariant");
347   const ObjectSampleRootDescriptionInfo* const osdi = (const ObjectSampleRootDescriptionInfo*)di;
348   writer->write(osdi->_id);
349   writer->write(description(osdi));
350   writer->write<u8>(osdi->_data._system);
351   writer->write<u8>(osdi->_data._type);
352   return 1;
353 }
354 
get_gc_root_description_info_id(const Edge & edge,traceid id)355 static traceid get_gc_root_description_info_id(const Edge& edge, traceid id) {
356   assert(edge.is_root(), "invariant");
357   if (EdgeUtils::is_leak_edge(edge)) {
358     return 0;
359   }
360 
361   if (root_infos == NULL) {
362     root_infos = new RootDescriptionInfo();
363   }
364   assert(root_infos != NULL, "invariant");
365   ObjectSampleRootDescriptionInfo* const oodi = new ObjectSampleRootDescriptionInfo();
366   oodi->_id = id;
367   oodi->_data._root_edge = &edge;
368   return root_infos->store(oodi);
369 }
370 
371 typedef JfrTypeWriterImplHost<const ObjectSampleRootDescriptionInfo*, __write_root_description_info__> RootDescriptionWriterImpl;
372 typedef JfrTypeWriterHost<RootDescriptionWriterImpl, TYPE_OLDOBJECTGCROOT> RootDescriptionWriter;
373 
374 
_edge_reference_compare_(uintptr_t lhs,uintptr_t rhs)375 int _edge_reference_compare_(uintptr_t lhs, uintptr_t rhs) {
376   return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0;
377 }
378 
_root_desc_compare_(const ObjectSampleRootDescriptionInfo * const & lhs,const ObjectSampleRootDescriptionInfo * const & rhs)379 int _root_desc_compare_(const ObjectSampleRootDescriptionInfo*const & lhs, const ObjectSampleRootDescriptionInfo* const& rhs) {
380   const uintptr_t lhs_ref = (uintptr_t)lhs->_data._root_edge->reference();
381   const uintptr_t rhs_ref = (uintptr_t)rhs->_data._root_edge->reference();
382   return _edge_reference_compare_(lhs_ref, rhs_ref);
383 }
384 
find_sorted(const RootCallbackInfo & callback_info,const GrowableArray<const ObjectSampleRootDescriptionInfo * > * arr,int length,bool & found)385 static int find_sorted(const RootCallbackInfo& callback_info,
386                        const GrowableArray<const ObjectSampleRootDescriptionInfo*>* arr,
387                        int length,
388                        bool& found) {
389   assert(arr != NULL, "invariant");
390   assert(length >= 0, "invariant");
391   assert(length <= arr->length(), "invariant");
392 
393   found = false;
394   int min = 0;
395   int max = length;
396   while (max >= min) {
397     const int mid = (int)(((uint)max + min) / 2);
398     int diff = _edge_reference_compare_((uintptr_t)callback_info._high,
399                                         (uintptr_t)arr->at(mid)->_data._root_edge->reference());
400     if (diff > 0) {
401       min = mid + 1;
402     } else if (diff < 0) {
403       max = mid - 1;
404     } else {
405       found = true;
406       return mid;
407     }
408   }
409   return min;
410 }
411 
412 class RootResolutionSet : public ResourceObj, public RootCallback {
413  private:
414   GrowableArray<const ObjectSampleRootDescriptionInfo*>* _unresolved_roots;
415 
high() const416   const uintptr_t high() const {
417     return (uintptr_t)_unresolved_roots->last()->_data._root_edge->reference();
418   }
419 
low() const420   const uintptr_t low() const {
421     return (uintptr_t)_unresolved_roots->first()->_data._root_edge->reference();
422   }
423 
in_set_address_range(const RootCallbackInfo & callback_info) const424   bool in_set_address_range(const RootCallbackInfo& callback_info) const {
425     assert(callback_info._low == NULL, "invariant");
426     const uintptr_t addr = (uintptr_t)callback_info._high;
427     return low() <= addr && high() >= addr;
428   }
429 
compare_to_range(const RootCallbackInfo & callback_info) const430   int compare_to_range(const RootCallbackInfo& callback_info) const {
431     assert(callback_info._high != NULL, "invariant");
432     assert(callback_info._low != NULL, "invariant");
433 
434     for (int i = 0; i < _unresolved_roots->length(); ++i) {
435       const uintptr_t ref_addr = (uintptr_t)_unresolved_roots->at(i)->_data._root_edge->reference();
436       if ((uintptr_t)callback_info._low <= ref_addr && (uintptr_t)callback_info._high >= ref_addr) {
437         return i;
438       }
439     }
440     return -1;
441   }
442 
exact(const RootCallbackInfo & callback_info) const443   int exact(const RootCallbackInfo& callback_info) const {
444     assert(callback_info._high != NULL, "invariant");
445     assert(in_set_address_range(callback_info), "invariant");
446 
447     bool found;
448     const int idx = find_sorted(callback_info, _unresolved_roots, _unresolved_roots->length(), found);
449     return found ? idx : -1;
450   }
451 
resolve_root(const RootCallbackInfo & callback_info,int idx) const452   bool resolve_root(const RootCallbackInfo& callback_info, int idx) const {
453     assert(idx >= 0, "invariant");
454     assert(idx < _unresolved_roots->length(), "invariant");
455 
456     ObjectSampleRootDescriptionInfo* const desc =
457       const_cast<ObjectSampleRootDescriptionInfo*>(_unresolved_roots->at(idx));
458     assert(desc != NULL, "invariant");
459     assert((uintptr_t)callback_info._high == (uintptr_t)desc->_data._root_edge->reference(), "invariant");
460 
461     desc->_data._system = callback_info._system;
462     desc->_data._type = callback_info._type;
463 
464     if (callback_info._system == OldObjectRoot::_threads) {
465       const JavaThread* jt = (const JavaThread*)callback_info._context;
466       assert(jt != NULL, "invariant");
467       desc->_data._description = jt->name();
468     }
469 
470     _unresolved_roots->remove_at(idx);
471     return _unresolved_roots->is_empty();
472   }
473 
474  public:
RootResolutionSet(RootDescriptionInfo * info)475   RootResolutionSet(RootDescriptionInfo* info) : _unresolved_roots(NULL) {
476     assert(info != NULL, "invariant");
477     // construct a sorted copy
478     const GrowableArray<const ObjectSampleRootDescriptionInfo*>& info_storage = info->storage();
479     const int length = info_storage.length();
480     _unresolved_roots = new GrowableArray<const ObjectSampleRootDescriptionInfo*>(length);
481     assert(_unresolved_roots != NULL, "invariant");
482 
483     for (int i = 0; i < length; ++i) {
484       _unresolved_roots->insert_sorted<_root_desc_compare_>(info_storage.at(i));
485     }
486   }
487 
process(const RootCallbackInfo & callback_info)488   bool process(const RootCallbackInfo& callback_info) {
489     if (NULL == callback_info._low) {
490       if (in_set_address_range(callback_info)) {
491         const int idx = exact(callback_info);
492         return idx == -1 ? false : resolve_root(callback_info, idx);
493       }
494       return false;
495     }
496     assert(callback_info._low != NULL, "invariant");
497     const int idx = compare_to_range(callback_info);
498     return idx == -1 ? false : resolve_root(callback_info, idx);
499   }
500 
entries() const501   int entries() const {
502     return _unresolved_roots->length();
503   }
504 
at(int idx) const505   const void* at(int idx) const {
506     assert(idx >= 0, "invariant");
507     assert(idx < _unresolved_roots->length(), "invariant");
508     return _unresolved_roots->at(idx)->_data._root_edge->reference();
509   }
510 };
511 
write_root_descriptors(JfrCheckpointWriter & writer)512 static void write_root_descriptors(JfrCheckpointWriter& writer) {
513   if (root_infos != NULL) {
514     // resolve roots
515     RootResolutionSet rrs(root_infos);
516     RootResolver::resolve(rrs);
517     // write roots
518     RootDescriptionWriter rw(&writer);
519     root_infos->iterate(rw);
520   }
521 }
522 
add_old_object_sample_info(const StoredEdge * current,traceid id)523 static void add_old_object_sample_info(const StoredEdge* current, traceid id) {
524   assert(current != NULL, "invariant");
525   if (sample_infos == NULL) {
526     sample_infos = new SampleInfo();
527   }
528   assert(sample_infos != NULL, "invariant");
529   OldObjectSampleInfo* const oosi = new OldObjectSampleInfo();
530   assert(oosi != NULL, "invariant");
531   oosi->_id = id;
532   oosi->_data._object = current->pointee();
533   oosi->_data._reference_id = current->parent() == NULL ? 0 : id;
534   sample_infos->store(oosi);
535 }
536 
add_reference_info(const StoredEdge * current,traceid id,traceid parent_id)537 static void add_reference_info(const StoredEdge* current, traceid id, traceid parent_id) {
538   assert(current != NULL, "invariant");
539   if (ref_infos == NULL) {
540     ref_infos = new RefInfo();
541   }
542 
543   assert(ref_infos != NULL, "invariant");
544   ReferenceInfo* const ri = new ReferenceInfo();
545   assert(ri != NULL, "invariant");
546 
547   ri->_id = id;
548   ri->_data._array_info_id = current->is_skip_edge() ? 0 : get_array_info_id(*current, id);
549   ri->_data._field_info_id = ri->_data._array_info_id != 0 || current->is_skip_edge() ? 0 : get_field_info_id(*current);
550   ri->_data._old_object_sample_id = parent_id;
551   ri->_data._skip = current->skip_length();
552   ref_infos->store(ri);
553 }
554 
is_gc_root(const StoredEdge * current)555 static bool is_gc_root(const StoredEdge* current) {
556   assert(current != NULL, "invariant");
557   return current->parent() == NULL && current->gc_root_id() != 0;
558 }
559 
add_gc_root_info(const StoredEdge * root,traceid id)560 static traceid add_gc_root_info(const StoredEdge* root, traceid id) {
561   assert(root != NULL, "invariant");
562   assert(is_gc_root(root), "invariant");
563   return get_gc_root_description_info_id(*root, id);
564 }
565 
write(const StoredEdge * edge)566 void ObjectSampleWriter::write(const StoredEdge* edge) {
567   assert(edge != NULL, "invariant");
568   const traceid id = _store->get_id(edge);
569   add_old_object_sample_info(edge, id);
570   const StoredEdge* const parent = edge->parent();
571   if (parent != NULL) {
572     add_reference_info(edge, id, _store->get_id(parent));
573     return;
574   }
575   if (is_gc_root(edge)) {
576     assert(edge->gc_root_id() == id, "invariant");
577     add_gc_root_info(edge, id);
578   }
579 }
580 
581 class RootSystemType : public JfrSerializer {
582  public:
serialize(JfrCheckpointWriter & writer)583   void serialize(JfrCheckpointWriter& writer) {
584     const u4 nof_root_systems = OldObjectRoot::_number_of_systems;
585     writer.write_count(nof_root_systems);
586     for (u4 i = 0; i < nof_root_systems; ++i) {
587       writer.write_key(i);
588       writer.write(OldObjectRoot::system_description((OldObjectRoot::System)i));
589     }
590   }
591 };
592 
593 class RootType : public JfrSerializer {
594  public:
serialize(JfrCheckpointWriter & writer)595   void serialize(JfrCheckpointWriter& writer) {
596     const u4 nof_root_types = OldObjectRoot::_number_of_types;
597     writer.write_count(nof_root_types);
598     for (u4 i = 0; i < nof_root_types; ++i) {
599       writer.write_key(i);
600       writer.write(OldObjectRoot::type_description((OldObjectRoot::Type)i));
601     }
602   }
603 };
604 
register_serializers()605 static void register_serializers() {
606   static bool is_registered = false;
607   if (!is_registered) {
608     JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTSYSTEM, false, true, new RootSystemType());
609     JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTTYPE, false, true, new RootType());
610     is_registered = true;
611   }
612 }
613 
ObjectSampleWriter(JfrCheckpointWriter & writer,EdgeStore * store)614 ObjectSampleWriter::ObjectSampleWriter(JfrCheckpointWriter& writer, EdgeStore* store) :
615   _writer(writer),
616   _store(store) {
617   assert(store != NULL, "invariant");
618   assert(!store->is_empty(), "invariant");
619   register_serializers();
620   sample_infos = NULL;
621   ref_infos = NULL;
622   array_infos = NULL;
623   field_infos = NULL;
624   root_infos = NULL;
625 }
626 
~ObjectSampleWriter()627 ObjectSampleWriter::~ObjectSampleWriter() {
628   write_sample_infos(_writer);
629   write_reference_infos(_writer);
630   write_array_infos(_writer);
631   write_field_infos(_writer);
632   write_root_descriptors(_writer);
633 }
634 
operator ()(StoredEdge & e)635 bool ObjectSampleWriter::operator()(StoredEdge& e) {
636   write(&e);
637   return true;
638 }
639