1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/vm/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp Mon Aug 12 18:30:40 2019 +0300 1.3 @@ -0,0 +1,615 @@ 1.4 +/* 1.5 + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + * 1.26 + */ 1.27 + 1.28 +#include "precompiled.hpp" 1.29 +#include "jfrfiles/jfrTypes.hpp" 1.30 +#include "jfr/leakprofiler/chains/edge.hpp" 1.31 +#include "jfr/leakprofiler/chains/edgeStore.hpp" 1.32 +#include "jfr/leakprofiler/chains/edgeUtils.hpp" 1.33 +#include "jfr/leakprofiler/checkpoint/objectSampleDescription.hpp" 1.34 +#include "jfr/leakprofiler/checkpoint/objectSampleWriter.hpp" 1.35 +#include "jfr/leakprofiler/checkpoint/rootResolver.hpp" 1.36 +#include "jfr/leakprofiler/sampling/objectSampler.hpp" 1.37 +#include "jfr/leakprofiler/utilities/rootType.hpp" 1.38 +#include "jfr/leakprofiler/utilities/unifiedOop.hpp" 1.39 +#include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp" 1.40 +#include "jfr/recorder/checkpoint/types/jfrTypeSetWriter.hpp" 1.41 +#include "oops/oop.inline.hpp" 1.42 +#include "oops/symbol.hpp" 1.43 +#include "utilities/growableArray.hpp" 1.44 + 1.45 +template <typename Data> 1.46 +class ObjectSampleAuxInfo : public ResourceObj { 1.47 + public: 1.48 + Data _data; 1.49 + traceid _id; 1.50 + ObjectSampleAuxInfo() : _data(), _id(0) {} 1.51 +}; 1.52 + 1.53 +class ObjectSampleArrayData { 1.54 + public: 1.55 + int _array_size; 1.56 + int _array_index; 1.57 + ObjectSampleArrayData() : _array_size(0), _array_index(0) {} 1.58 +}; 1.59 + 1.60 +class ObjectSampleFieldInfo : public ResourceObj { 1.61 + public: 1.62 + const Symbol* _field_name_symbol; 1.63 + jshort _field_modifiers; 1.64 + ObjectSampleFieldInfo() : _field_name_symbol(NULL), _field_modifiers(0) {} 1.65 +}; 1.66 + 1.67 +class ObjectSampleRootDescriptionData { 1.68 + public: 1.69 + const Edge* _root_edge; 1.70 + const char* _description; 1.71 + OldObjectRoot::System _system; 1.72 + OldObjectRoot::Type _type; 1.73 + ObjectSampleRootDescriptionData() : _root_edge(NULL), 1.74 + _description(NULL), 1.75 + _system(OldObjectRoot::_system_undetermined), 1.76 + _type(OldObjectRoot::_type_undetermined) {} 1.77 +}; 1.78 + 1.79 +class OldObjectSampleData { 1.80 + public: 1.81 + oop _object; 1.82 + traceid _reference_id; 1.83 +}; 1.84 + 1.85 +class ReferenceData { 1.86 + public: 1.87 + traceid _field_info_id; 1.88 + traceid _array_info_id; 1.89 + traceid _old_object_sample_id; 1.90 + size_t _skip; 1.91 +}; 1.92 + 1.93 +static int initial_storage_size = 16; 1.94 + 1.95 +template <typename Data> 1.96 +class SampleSet : public ResourceObj { 1.97 + private: 1.98 + GrowableArray<Data>* _storage; 1.99 + public: 1.100 + SampleSet() : _storage(NULL) {} 1.101 + 1.102 + traceid store(Data data) { 1.103 + assert(data != NULL, "invariant"); 1.104 + if (_storage == NULL) { 1.105 + _storage = new GrowableArray<Data>(initial_storage_size); 1.106 + } 1.107 + assert(_storage != NULL, "invariant"); 1.108 + assert(_storage->find(data) == -1, "invariant"); 1.109 + _storage->append(data); 1.110 + return data->_id; 1.111 + } 1.112 + 1.113 + size_t size() const { 1.114 + return _storage != NULL ? (size_t)_storage->length() : 0; 1.115 + } 1.116 + 1.117 + template <typename Functor> 1.118 + void iterate(Functor& functor) { 1.119 + if (_storage != NULL) { 1.120 + for (int i = 0; i < _storage->length(); ++i) { 1.121 + functor(_storage->at(i)); 1.122 + } 1.123 + } 1.124 + } 1.125 + 1.126 + const GrowableArray<Data>& storage() const { 1.127 + return *_storage; 1.128 + } 1.129 +}; 1.130 + 1.131 +typedef ObjectSampleAuxInfo<ObjectSampleArrayData> ObjectSampleArrayInfo; 1.132 +typedef ObjectSampleAuxInfo<ObjectSampleRootDescriptionData> ObjectSampleRootDescriptionInfo; 1.133 +typedef ObjectSampleAuxInfo<OldObjectSampleData> OldObjectSampleInfo; 1.134 +typedef ObjectSampleAuxInfo<ReferenceData> ReferenceInfo; 1.135 + 1.136 +class FieldTable : public ResourceObj { 1.137 + template <typename, 1.138 + typename, 1.139 + template<typename, typename> class, 1.140 + typename, 1.141 + size_t> 1.142 + friend class HashTableHost; 1.143 + typedef HashTableHost<const ObjectSampleFieldInfo*, traceid, Entry, FieldTable, 109> FieldInfoTable; 1.144 + public: 1.145 + typedef FieldInfoTable::HashEntry FieldInfoEntry; 1.146 + 1.147 + private: 1.148 + static traceid _field_id_counter; 1.149 + FieldInfoTable* _table; 1.150 + 1.151 + void assign_id(FieldInfoEntry* entry) { 1.152 + assert(entry != NULL, "invariant"); 1.153 + entry->set_id(++_field_id_counter); 1.154 + } 1.155 + 1.156 + bool equals(const ObjectSampleFieldInfo* query, uintptr_t hash, const FieldInfoEntry* entry) { 1.157 + assert(hash == entry->hash(), "invariant"); 1.158 + assert(query != NULL, "invariant"); 1.159 + const ObjectSampleFieldInfo* stored = entry->literal(); 1.160 + assert(stored != NULL, "invariant"); 1.161 + assert(((Symbol*)stored->_field_name_symbol)->identity_hash() == ((Symbol*)query->_field_name_symbol)->identity_hash(), "invariant"); 1.162 + return stored->_field_modifiers == query->_field_modifiers; 1.163 + } 1.164 + 1.165 + public: 1.166 + FieldTable() : _table(new FieldInfoTable(this)) {} 1.167 + ~FieldTable() { 1.168 + assert(_table != NULL, "invariant"); 1.169 + delete _table; 1.170 + } 1.171 + 1.172 + traceid store(const ObjectSampleFieldInfo* field_info) { 1.173 + assert(field_info != NULL, "invariant"); 1.174 + const FieldInfoEntry& entry =_table->lookup_put(field_info, 1.175 + ((Symbol*)field_info->_field_name_symbol)->identity_hash()); 1.176 + return entry.id(); 1.177 + } 1.178 + 1.179 + size_t size() const { 1.180 + return _table->cardinality(); 1.181 + } 1.182 + 1.183 + template <typename T> 1.184 + void iterate(T& functor) const { 1.185 + _table->iterate_entry<T>(functor); 1.186 + } 1.187 +}; 1.188 + 1.189 +traceid FieldTable::_field_id_counter = 0; 1.190 + 1.191 +typedef SampleSet<const OldObjectSampleInfo*> SampleInfo; 1.192 +typedef SampleSet<const ReferenceInfo*> RefInfo; 1.193 +typedef SampleSet<const ObjectSampleArrayInfo*> ArrayInfo; 1.194 +typedef SampleSet<const ObjectSampleRootDescriptionInfo*> RootDescriptionInfo; 1.195 + 1.196 +static SampleInfo* sample_infos = NULL; 1.197 +static RefInfo* ref_infos = NULL; 1.198 +static ArrayInfo* array_infos = NULL; 1.199 +static FieldTable* field_infos = NULL; 1.200 +static RootDescriptionInfo* root_infos = NULL; 1.201 + 1.202 +int __write_sample_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* si) { 1.203 + assert(writer != NULL, "invariant"); 1.204 + assert(si != NULL, "invariant"); 1.205 + const OldObjectSampleInfo* const oosi = (const OldObjectSampleInfo*)si; 1.206 + oop object = oosi->_data._object; 1.207 + assert(object != NULL, "invariant"); 1.208 + writer->write(oosi->_id); 1.209 + writer->write((u8)(const HeapWord*)object); 1.210 + writer->write(const_cast<const Klass*>(object->klass())); 1.211 + ObjectSampleDescription od(object); 1.212 + writer->write(od.description()); 1.213 + writer->write(oosi->_data._reference_id); 1.214 + return 1; 1.215 +} 1.216 + 1.217 +typedef JfrArtifactWriterImplHost<const OldObjectSampleInfo*, __write_sample_info__> SampleWriterImpl; 1.218 +typedef JfrArtifactWriterHost<SampleWriterImpl, TYPE_OLDOBJECT> SampleWriter; 1.219 + 1.220 +static void write_sample_infos(JfrCheckpointWriter& writer) { 1.221 + if (sample_infos != NULL) { 1.222 + SampleWriter sw(&writer, NULL, false); 1.223 + sample_infos->iterate(sw); 1.224 + } 1.225 +} 1.226 + 1.227 +int __write_reference_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* ri) { 1.228 + assert(writer != NULL, "invariant"); 1.229 + assert(ri != NULL, "invariant"); 1.230 + const ReferenceInfo* const ref_info = (const ReferenceInfo*)ri; 1.231 + writer->write(ref_info->_id); 1.232 + writer->write(ref_info->_data._array_info_id); 1.233 + writer->write(ref_info->_data._field_info_id); 1.234 + writer->write(ref_info->_data._old_object_sample_id); 1.235 + writer->write<s4>((s4)ref_info->_data._skip); 1.236 + return 1; 1.237 +} 1.238 + 1.239 +typedef JfrArtifactWriterImplHost<const ReferenceInfo*, __write_reference_info__> ReferenceWriterImpl; 1.240 +typedef JfrArtifactWriterHost<ReferenceWriterImpl, TYPE_REFERENCE> ReferenceWriter; 1.241 + 1.242 +static void write_reference_infos(JfrCheckpointWriter& writer) { 1.243 + if (ref_infos != NULL) { 1.244 + ReferenceWriter rw(&writer, NULL, false); 1.245 + ref_infos->iterate(rw); 1.246 + } 1.247 +} 1.248 + 1.249 +int __write_array_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* ai) { 1.250 + assert(writer != NULL, "invariant"); 1.251 + assert(ai != NULL, "invariant"); 1.252 + const ObjectSampleArrayInfo* const osai = (const ObjectSampleArrayInfo*)ai; 1.253 + writer->write(osai->_id); 1.254 + writer->write(osai->_data._array_size); 1.255 + writer->write(osai->_data._array_index); 1.256 + return 1; 1.257 +} 1.258 + 1.259 +static traceid get_array_info_id(const Edge& edge, traceid id) { 1.260 + if (edge.is_root() || !EdgeUtils::is_array_element(edge)) { 1.261 + return 0; 1.262 + } 1.263 + if (array_infos == NULL) { 1.264 + array_infos = new ArrayInfo(); 1.265 + } 1.266 + assert(array_infos != NULL, "invariant"); 1.267 + 1.268 + ObjectSampleArrayInfo* const osai = new ObjectSampleArrayInfo(); 1.269 + assert(osai != NULL, "invariant"); 1.270 + osai->_id = id; 1.271 + osai->_data._array_size = EdgeUtils::array_size(edge); 1.272 + osai->_data._array_index = EdgeUtils::array_index(edge); 1.273 + return array_infos->store(osai); 1.274 +} 1.275 + 1.276 +typedef JfrArtifactWriterImplHost<const ObjectSampleArrayInfo*, __write_array_info__> ArrayWriterImpl; 1.277 +typedef JfrArtifactWriterHost<ArrayWriterImpl, TYPE_OLDOBJECTARRAY> ArrayWriter; 1.278 + 1.279 +static void write_array_infos(JfrCheckpointWriter& writer) { 1.280 + if (array_infos != NULL) { 1.281 + ArrayWriter aw(&writer, NULL, false); 1.282 + array_infos->iterate(aw); 1.283 + } 1.284 +} 1.285 + 1.286 +int __write_field_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* fi) { 1.287 + assert(writer != NULL, "invariant"); 1.288 + assert(fi != NULL, "invariant"); 1.289 + const FieldTable::FieldInfoEntry* field_info_entry = (const FieldTable::FieldInfoEntry*)fi; 1.290 + writer->write(field_info_entry->id()); 1.291 + const ObjectSampleFieldInfo* const osfi = field_info_entry->literal(); 1.292 + writer->write(osfi->_field_name_symbol->as_C_string()); 1.293 + writer->write(osfi->_field_modifiers); 1.294 + return 1; 1.295 +} 1.296 + 1.297 +static traceid get_field_info_id(const Edge& edge) { 1.298 + if (edge.is_root()) { 1.299 + return 0; 1.300 + } 1.301 + 1.302 + assert(!EdgeUtils::is_array_element(edge), "invariant"); 1.303 + const Symbol* const field_name_symbol = EdgeUtils::field_name_symbol(edge); 1.304 + if (field_name_symbol == NULL) { 1.305 + return 0; 1.306 + } 1.307 + 1.308 + if (field_infos == NULL) { 1.309 + field_infos = new FieldTable(); 1.310 + } 1.311 + assert(field_infos != NULL, "invariant"); 1.312 + 1.313 + ObjectSampleFieldInfo* const osfi = new ObjectSampleFieldInfo(); 1.314 + assert(osfi != NULL, "invariant"); 1.315 + osfi->_field_name_symbol = field_name_symbol; 1.316 + osfi->_field_modifiers = EdgeUtils::field_modifiers(edge); 1.317 + return field_infos->store(osfi); 1.318 +} 1.319 + 1.320 +typedef JfrArtifactWriterImplHost<const FieldTable::FieldInfoEntry*, __write_field_info__> FieldWriterImpl; 1.321 +typedef JfrArtifactWriterHost<FieldWriterImpl, TYPE_OLDOBJECTFIELD> FieldWriter; 1.322 + 1.323 +static void write_field_infos(JfrCheckpointWriter& writer) { 1.324 + if (field_infos != NULL) { 1.325 + FieldWriter fw(&writer, NULL, false); 1.326 + field_infos->iterate(fw); 1.327 + } 1.328 +} 1.329 + 1.330 +static const char* description(const ObjectSampleRootDescriptionInfo* osdi) { 1.331 + assert(osdi != NULL, "invariant"); 1.332 + 1.333 + if (osdi->_data._description == NULL) { 1.334 + return NULL; 1.335 + } 1.336 + 1.337 + ObjectDescriptionBuilder description; 1.338 + if (osdi->_data._system == OldObjectRoot::_threads) { 1.339 + description.write_text("Thread Name: "); 1.340 + } 1.341 + description.write_text(osdi->_data._description); 1.342 + return description.description(); 1.343 +} 1.344 + 1.345 +int __write_root_description_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* di) { 1.346 + assert(writer != NULL, "invariant"); 1.347 + assert(di != NULL, "invariant"); 1.348 + const ObjectSampleRootDescriptionInfo* const osdi = (const ObjectSampleRootDescriptionInfo*)di; 1.349 + writer->write(osdi->_id); 1.350 + writer->write(description(osdi)); 1.351 + writer->write<u8>(osdi->_data._system); 1.352 + writer->write<u8>(osdi->_data._type); 1.353 + return 1; 1.354 +} 1.355 + 1.356 +static traceid get_root_description_info_id(const Edge& edge, traceid id) { 1.357 + assert(edge.is_root(), "invariant"); 1.358 + if (EdgeUtils::is_leak_edge(edge)) { 1.359 + return 0; 1.360 + } 1.361 + 1.362 + if (root_infos == NULL) { 1.363 + root_infos = new RootDescriptionInfo(); 1.364 + } 1.365 + assert(root_infos != NULL, "invariant"); 1.366 + ObjectSampleRootDescriptionInfo* const oodi = new ObjectSampleRootDescriptionInfo(); 1.367 + oodi->_id = id; 1.368 + oodi->_data._root_edge = &edge; 1.369 + return root_infos->store(oodi); 1.370 +} 1.371 + 1.372 +typedef JfrArtifactWriterImplHost<const ObjectSampleRootDescriptionInfo*, __write_root_description_info__> RootDescriptionWriterImpl; 1.373 +typedef JfrArtifactWriterHost<RootDescriptionWriterImpl, TYPE_OLDOBJECTGCROOT> RootDescriptionWriter; 1.374 + 1.375 + 1.376 +int _edge_reference_compare_(uintptr_t lhs, uintptr_t rhs) { 1.377 + return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; 1.378 +} 1.379 + 1.380 +int _root_desc_compare_(const ObjectSampleRootDescriptionInfo*const & lhs, const ObjectSampleRootDescriptionInfo* const& rhs) { 1.381 + const uintptr_t lhs_ref = (uintptr_t)lhs->_data._root_edge->reference(); 1.382 + const uintptr_t rhs_ref = (uintptr_t)rhs->_data._root_edge->reference(); 1.383 + return _edge_reference_compare_(lhs_ref, rhs_ref); 1.384 +} 1.385 + 1.386 +static int find_sorted(const RootCallbackInfo& callback_info, 1.387 + const GrowableArray<const ObjectSampleRootDescriptionInfo*>* arr, 1.388 + int length, 1.389 + bool& found) { 1.390 + assert(arr != NULL, "invariant"); 1.391 + assert(length >= 0, "invariant"); 1.392 + assert(length <= arr->length(), "invariant"); 1.393 + 1.394 + found = false; 1.395 + int min = 0; 1.396 + int max = length; 1.397 + while (max >= min) { 1.398 + const int mid = (int)(((uint)max + min) / 2); 1.399 + int diff = _edge_reference_compare_((uintptr_t)callback_info._high, 1.400 + (uintptr_t)arr->at(mid)->_data._root_edge->reference()); 1.401 + if (diff > 0) { 1.402 + min = mid + 1; 1.403 + } else if (diff < 0) { 1.404 + max = mid - 1; 1.405 + } else { 1.406 + found = true; 1.407 + return mid; 1.408 + } 1.409 + } 1.410 + return min; 1.411 +} 1.412 + 1.413 +class RootResolutionSet : public ResourceObj, public RootCallback { 1.414 + private: 1.415 + GrowableArray<const ObjectSampleRootDescriptionInfo*>* _unresolved_roots; 1.416 + 1.417 + const uintptr_t high() const { 1.418 + return (uintptr_t)_unresolved_roots->top()->_data._root_edge->reference(); 1.419 + } 1.420 + 1.421 + const uintptr_t low() const { 1.422 + return (uintptr_t)_unresolved_roots->first()->_data._root_edge->reference(); 1.423 + } 1.424 + 1.425 + bool in_set_address_range(const RootCallbackInfo& callback_info) const { 1.426 + assert(callback_info._low == NULL, "invariant"); 1.427 + const uintptr_t addr = (uintptr_t)callback_info._high; 1.428 + return low() <= addr && high() >= addr; 1.429 + } 1.430 + 1.431 + int compare_to_range(const RootCallbackInfo& callback_info) const { 1.432 + assert(callback_info._high != NULL, "invariant"); 1.433 + assert(callback_info._low != NULL, "invariant"); 1.434 + 1.435 + for (int i = 0; i < _unresolved_roots->length(); ++i) { 1.436 + const uintptr_t ref_addr = (uintptr_t)_unresolved_roots->at(i)->_data._root_edge->reference(); 1.437 + if ((uintptr_t)callback_info._low <= ref_addr && (uintptr_t)callback_info._high >= ref_addr) { 1.438 + return i; 1.439 + } 1.440 + } 1.441 + return -1; 1.442 + } 1.443 + 1.444 + int exact(const RootCallbackInfo& callback_info) const { 1.445 + assert(callback_info._high != NULL, "invariant"); 1.446 + assert(in_set_address_range(callback_info), "invariant"); 1.447 + 1.448 + bool found; 1.449 + const int idx = find_sorted(callback_info, _unresolved_roots, _unresolved_roots->length(), found); 1.450 + return found ? idx : -1; 1.451 + } 1.452 + 1.453 + bool resolve_root(const RootCallbackInfo& callback_info, int idx) const { 1.454 + assert(idx >= 0, "invariant"); 1.455 + assert(idx < _unresolved_roots->length(), "invariant"); 1.456 + 1.457 + ObjectSampleRootDescriptionInfo* const desc = 1.458 + const_cast<ObjectSampleRootDescriptionInfo*>(_unresolved_roots->at(idx)); 1.459 + assert(desc != NULL, "invariant"); 1.460 + assert((uintptr_t)callback_info._high == (uintptr_t)desc->_data._root_edge->reference(), "invariant"); 1.461 + 1.462 + desc->_data._system = callback_info._system; 1.463 + desc->_data._type = callback_info._type; 1.464 + 1.465 + if (callback_info._system == OldObjectRoot::_threads) { 1.466 + const JavaThread* jt = (const JavaThread*)callback_info._context; 1.467 + assert(jt != NULL, "invariant"); 1.468 + desc->_data._description = jt->name(); 1.469 + } 1.470 + 1.471 + _unresolved_roots->remove_at(idx); 1.472 + return _unresolved_roots->is_empty(); 1.473 + } 1.474 + 1.475 + public: 1.476 + RootResolutionSet(RootDescriptionInfo* info) : _unresolved_roots(NULL) { 1.477 + assert(info != NULL, "invariant"); 1.478 + // construct a sorted copy 1.479 + const GrowableArray<const ObjectSampleRootDescriptionInfo*>& info_storage = info->storage(); 1.480 + const int length = info_storage.length(); 1.481 + _unresolved_roots = new GrowableArray<const ObjectSampleRootDescriptionInfo*>(length); 1.482 + assert(_unresolved_roots != NULL, "invariant"); 1.483 + 1.484 + for (int i = 0; i < length; ++i) { 1.485 + _unresolved_roots->insert_sorted<_root_desc_compare_>(info_storage.at(i)); 1.486 + } 1.487 + } 1.488 + 1.489 + bool process(const RootCallbackInfo& callback_info) { 1.490 + if (NULL == callback_info._low) { 1.491 + if (in_set_address_range(callback_info)) { 1.492 + const int idx = exact(callback_info); 1.493 + return idx == -1 ? false : resolve_root(callback_info, idx); 1.494 + } 1.495 + return false; 1.496 + } 1.497 + assert(callback_info._low != NULL, "invariant"); 1.498 + const int idx = compare_to_range(callback_info); 1.499 + return idx == -1 ? false : resolve_root(callback_info, idx); 1.500 + } 1.501 + 1.502 + int entries() const { 1.503 + return _unresolved_roots->length(); 1.504 + } 1.505 + 1.506 + const void* at(int idx) const { 1.507 + assert(idx >= 0, "invariant"); 1.508 + assert(idx < _unresolved_roots->length(), "invariant"); 1.509 + return _unresolved_roots->at(idx)->_data._root_edge->reference(); 1.510 + } 1.511 +}; 1.512 + 1.513 +static void write_root_descriptors(JfrCheckpointWriter& writer) { 1.514 + if (root_infos != NULL) { 1.515 + // resolve roots 1.516 + RootResolutionSet rrs(root_infos); 1.517 + RootResolver::resolve(rrs); 1.518 + // write roots 1.519 + RootDescriptionWriter rw(&writer, NULL, false); 1.520 + root_infos->iterate(rw); 1.521 + } 1.522 +} 1.523 + 1.524 +static void add_old_object_sample_info(const Edge* current, traceid id) { 1.525 + assert(current != NULL, "invariant"); 1.526 + if (sample_infos == NULL) { 1.527 + sample_infos = new SampleInfo(); 1.528 + } 1.529 + assert(sample_infos != NULL, "invariant"); 1.530 + OldObjectSampleInfo* const oosi = new OldObjectSampleInfo(); 1.531 + assert(oosi != NULL, "invariant"); 1.532 + oosi->_id = id; 1.533 + oosi->_data._object = current->pointee(); 1.534 + oosi->_data._reference_id = current->is_root() ? (traceid)0 : id; 1.535 + sample_infos->store(oosi); 1.536 +} 1.537 + 1.538 +static void add_reference_info(const RoutableEdge* current, traceid id, traceid parent_id) { 1.539 + assert(current != NULL, "invariant"); 1.540 + if (ref_infos == NULL) { 1.541 + ref_infos = new RefInfo(); 1.542 + } 1.543 + 1.544 + assert(ref_infos != NULL, "invariant"); 1.545 + ReferenceInfo* const ri = new ReferenceInfo(); 1.546 + assert(ri != NULL, "invariant"); 1.547 + 1.548 + ri->_id = id; 1.549 + ri->_data._array_info_id = !current->is_skip_edge() ? get_array_info_id(*current, id) : 0; 1.550 + ri->_data._field_info_id = ri->_data._array_info_id == 0 && !current->is_skip_edge() ? 1.551 + get_field_info_id(*current) : (traceid)0; 1.552 + ri->_data._old_object_sample_id = parent_id; 1.553 + ri->_data._skip = current->skip_length(); 1.554 + ref_infos->store(ri); 1.555 +} 1.556 + 1.557 +static traceid add_root_info(const Edge* root, traceid id) { 1.558 + assert(root != NULL, "invariant"); 1.559 + assert(root->is_root(), "invariant"); 1.560 + return get_root_description_info_id(*root, id); 1.561 +} 1.562 + 1.563 +void ObjectSampleWriter::write(const RoutableEdge* edge) { 1.564 + assert(edge != NULL, "invariant"); 1.565 + const traceid id = _store->get_id(edge); 1.566 + add_old_object_sample_info(edge, id); 1.567 + const RoutableEdge* parent = edge->logical_parent(); 1.568 + if (parent != NULL) { 1.569 + add_reference_info(edge, id, _store->get_id(parent)); 1.570 + } else { 1.571 + assert(edge->is_root(), "invariant"); 1.572 + add_root_info(edge, id); 1.573 + } 1.574 +} 1.575 + 1.576 +ObjectSampleWriter::ObjectSampleWriter(JfrCheckpointWriter& writer, const EdgeStore* store) : 1.577 + _writer(writer), 1.578 + _store(store) { 1.579 + assert(store != NULL, "invariant"); 1.580 + assert(store->number_of_entries() > 0, "invariant"); 1.581 + sample_infos = NULL; 1.582 + ref_infos = NULL; 1.583 + array_infos = NULL; 1.584 + field_infos = NULL; 1.585 + root_infos = NULL; 1.586 +} 1.587 + 1.588 +ObjectSampleWriter::~ObjectSampleWriter() { 1.589 + write_sample_infos(_writer); 1.590 + write_reference_infos(_writer); 1.591 + write_array_infos(_writer); 1.592 + write_field_infos(_writer); 1.593 + write_root_descriptors(_writer); 1.594 +} 1.595 + 1.596 +void ObjectSampleWriter::write_chain(const RoutableEdge& edge) { 1.597 + assert(EdgeUtils::is_leak_edge(edge), "invariant"); 1.598 + if (edge.processed()) { 1.599 + return; 1.600 + } 1.601 + EdgeUtils::collapse_chain(edge); 1.602 + const RoutableEdge* current = &edge; 1.603 + while (current != NULL) { 1.604 + if (current->processed()) { 1.605 + return; 1.606 + } 1.607 + write(current); 1.608 + current->set_processed(); 1.609 + current = current->logical_parent(); 1.610 + } 1.611 +} 1.612 + 1.613 +bool ObjectSampleWriter::operator()(const RoutableEdge& edge) { 1.614 + if (EdgeUtils::is_leak_edge(edge)) { 1.615 + write_chain(edge); 1.616 + } 1.617 + return true; 1.618 +}