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