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 "jfr/leakprofiler/chains/edgeStore.hpp" 27 #include "jfr/leakprofiler/chains/edgeUtils.hpp" 28 #include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp" 29 #include "oops/oop.inline.hpp" 30 31 StoredEdge::StoredEdge(const Edge* parent, UnifiedOopRef reference) : Edge(parent, reference), _gc_root_id(0), _skip_length(0) {} 32 33 StoredEdge::StoredEdge(const Edge& edge) : Edge(edge), _gc_root_id(0), _skip_length(0) {} 34 35 StoredEdge::StoredEdge(const StoredEdge& edge) : Edge(edge), _gc_root_id(edge._gc_root_id), _skip_length(edge._skip_length) {} 36 37 traceid EdgeStore::_edge_id_counter = 0; 38 39 EdgeStore::EdgeStore() : _edges(NULL) { 40 _edges = new EdgeHashTable(this); 41 } 42 43 EdgeStore::~EdgeStore() { 44 assert(_edges != NULL, "invariant"); 45 delete _edges; 46 } 47 48 bool EdgeStore::is_empty() const { 49 return !_edges->has_entries(); 50 } 51 52 void EdgeStore::on_link(EdgeEntry* entry) { 53 assert(entry != NULL, "invariant"); 54 assert(entry->id() == 0, "invariant"); 55 entry->set_id(++_edge_id_counter); 56 } 57 58 bool EdgeStore::on_equals(uintptr_t hash, const EdgeEntry* entry) { 59 assert(entry != NULL, "invariant"); 60 assert(entry->hash() == hash, "invariant"); 61 return true; 62 } 63 64 void EdgeStore::on_unlink(EdgeEntry* entry) { 65 assert(entry != NULL, "invariant"); 66 // nothing 67 } 68 69 #ifdef ASSERT 70 bool EdgeStore::contains(UnifiedOopRef reference) const { 71 return get(reference) != NULL; 72 } 73 #endif 74 75 StoredEdge* EdgeStore::get(UnifiedOopRef reference) const { 76 assert(!reference.is_null(), "invariant"); 77 EdgeEntry* const entry = _edges->lookup_only(reference.addr<uintptr_t>()); 78 return entry != NULL ? entry->literal_addr() : NULL; 79 } 80 81 StoredEdge* EdgeStore::put(UnifiedOopRef reference) { 82 assert(!reference.is_null(), "invariant"); 83 const StoredEdge e(NULL, reference); 84 assert(NULL == _edges->lookup_only(reference.addr<uintptr_t>()), "invariant"); 85 EdgeEntry& entry = _edges->put(reference.addr<uintptr_t>(), e); 86 return entry.literal_addr(); 87 } 88 89 traceid EdgeStore::get_id(const Edge* edge) const { 90 assert(edge != NULL, "invariant"); 91 EdgeEntry* const entry = _edges->lookup_only(edge->reference().addr<uintptr_t>()); 92 assert(entry != NULL, "invariant"); 93 return entry->id(); 94 } 95 96 traceid EdgeStore::gc_root_id(const Edge* edge) const { 97 assert(edge != NULL, "invariant"); 98 const traceid gc_root_id = static_cast<const StoredEdge*>(edge)->gc_root_id(); 99 if (gc_root_id != 0) { 100 return gc_root_id; 101 } 102 // not cached 103 assert(edge != NULL, "invariant"); 104 const Edge* const root = EdgeUtils::root(*edge); 105 assert(root != NULL, "invariant"); 106 assert(root->parent() == NULL, "invariant"); 107 return get_id(root); 108 } 109 110 static const Edge* get_skip_ancestor(const Edge** current, size_t distance_to_root, size_t* skip_length) { 111 assert(distance_to_root >= EdgeUtils::root_context, "invariant"); 112 assert(*skip_length == 0, "invariant"); 113 *skip_length = distance_to_root - (EdgeUtils::root_context - 1); 114 const Edge* const target = EdgeUtils::ancestor(**current, *skip_length); 115 assert(target != NULL, "invariant"); 116 assert(target->distance_to_root() + 1 == EdgeUtils::root_context, "invariant"); 117 return target; 118 } 119 120 bool EdgeStore::put_skip_edge(StoredEdge** previous, const Edge** current, size_t distance_to_root) { 121 assert(*previous != NULL, "invariant"); 122 assert((*previous)->parent() == NULL, "invariant"); 123 assert(*current != NULL, "invariant"); 124 assert((*current)->distance_to_root() == distance_to_root, "invariant"); 125 126 if (distance_to_root < EdgeUtils::root_context) { 127 // nothing to skip 128 return false; 129 } 130 131 size_t skip_length = 0; 132 const Edge* const skip_ancestor = get_skip_ancestor(current, distance_to_root, &skip_length); 133 assert(skip_ancestor != NULL, "invariant"); 134 (*previous)->set_skip_length(skip_length); 135 136 // lookup target 137 StoredEdge* stored_target = get(skip_ancestor->reference()); 138 if (stored_target != NULL) { 139 (*previous)->set_parent(stored_target); 140 // linked to existing, complete 141 return true; 142 } 143 144 assert(stored_target == NULL, "invariant"); 145 stored_target = put(skip_ancestor->reference()); 146 assert(stored_target != NULL, "invariant"); 147 (*previous)->set_parent(stored_target); 148 *previous = stored_target; 149 *current = skip_ancestor->parent(); 150 return false; 151 } 152 153 static void link_edge(const StoredEdge* current_stored, StoredEdge** previous) { 154 assert(current_stored != NULL, "invariant"); 155 assert(*previous != NULL, "invariant"); 156 assert((*previous)->parent() == NULL, "invariant"); 157 (*previous)->set_parent(current_stored); 158 } 159 160 static const StoredEdge* find_closest_skip_edge(const StoredEdge* edge, size_t* distance) { 161 assert(edge != NULL, "invariant"); 162 assert(distance != NULL, "invariant"); 163 const StoredEdge* current = edge; 164 *distance = 1; 165 while (current != NULL && !current->is_skip_edge()) { 166 ++(*distance); 167 current = current->parent(); 168 } 169 return current; 170 } 171 172 void EdgeStore::link_with_existing_chain(const StoredEdge* current_stored, StoredEdge** previous, size_t previous_length) { 173 assert(current_stored != NULL, "invariant"); 174 assert((*previous)->parent() == NULL, "invariant"); 175 size_t distance_to_skip_edge; // including the skip edge itself 176 const StoredEdge* const closest_skip_edge = find_closest_skip_edge(current_stored, &distance_to_skip_edge); 177 if (closest_skip_edge == NULL) { 178 // no found skip edge implies root 179 if (distance_to_skip_edge + previous_length <= EdgeUtils::max_ref_chain_depth) { 180 link_edge(current_stored, previous); 181 return; 182 } 183 assert(current_stored->distance_to_root() == distance_to_skip_edge - 2, "invariant"); 184 put_skip_edge(previous, reinterpret_cast<const Edge**>(¤t_stored), distance_to_skip_edge - 2); 185 return; 186 } 187 assert(closest_skip_edge->is_skip_edge(), "invariant"); 188 if (distance_to_skip_edge + previous_length <= EdgeUtils::leak_context) { 189 link_edge(current_stored, previous); 190 return; 191 } 192 // create a new skip edge with derived information from closest skip edge 193 (*previous)->set_skip_length(distance_to_skip_edge + closest_skip_edge->skip_length()); 194 (*previous)->set_parent(closest_skip_edge->parent()); 195 } 196 197 StoredEdge* EdgeStore::link_new_edge(StoredEdge** previous, const Edge** current) { 198 assert(*previous != NULL, "invariant"); 199 assert((*previous)->parent() == NULL, "invariant"); 200 assert(*current != NULL, "invariant"); 201 assert(!contains((*current)->reference()), "invariant"); 202 StoredEdge* const stored_edge = put((*current)->reference()); 203 assert(stored_edge != NULL, "invariant"); 204 link_edge(stored_edge, previous); 205 return stored_edge; 206 } 207 208 bool EdgeStore::put_edges(StoredEdge** previous, const Edge** current, size_t limit) { 209 assert(*previous != NULL, "invariant"); 210 assert(*current != NULL, "invariant"); 211 size_t depth = 1; 212 while (*current != NULL && depth < limit) { 213 StoredEdge* stored_edge = get((*current)->reference()); 214 if (stored_edge != NULL) { 215 link_with_existing_chain(stored_edge, previous, depth); 216 return true; 217 } 218 stored_edge = link_new_edge(previous, current); 219 assert((*previous)->parent() != NULL, "invariant"); 220 *previous = stored_edge; 221 *current = (*current)->parent(); 222 ++depth; 223 } 224 return NULL == *current; 225 } 226 227 // Install the immediate edge into the mark word of the leak candidate object 228 StoredEdge* EdgeStore::associate_leak_context_with_candidate(const Edge* edge) { 229 assert(edge != NULL, "invariant"); 230 assert(!contains(edge->reference()), "invariant"); 231 StoredEdge* const leak_context_edge = put(edge->reference()); 232 oop sample_object = edge->pointee(); 233 assert(sample_object != NULL, "invariant"); 234 assert(sample_object->mark().is_marked(), "invariant"); 235 sample_object->set_mark(markWord::from_pointer(leak_context_edge)); 236 return leak_context_edge; 237 } 238 239 /* 240 * The purpose of put_chain() is to reify the edge sequence 241 * discovered during heap traversal with a normalized logical copy. 242 * This copy consist of two sub-sequences and a connecting link (skip edge). 243 * 244 * "current" can be thought of as the cursor (search) edge, it is not in the edge store. 245 * "previous" is always an edge in the edge store. 246 * The leak context edge is the edge adjacent to the leak candidate object, always an edge in the edge store. 247 */ 248 void EdgeStore::put_chain(const Edge* chain, size_t length) { 249 assert(chain != NULL, "invariant"); 250 assert(chain->distance_to_root() + 1 == length, "invariant"); 251 StoredEdge* const leak_context_edge = associate_leak_context_with_candidate(chain); 252 assert(leak_context_edge != NULL, "invariant"); 253 assert(leak_context_edge->parent() == NULL, "invariant"); 254 255 if (1 == length) { 256 store_gc_root_id_in_leak_context_edge(leak_context_edge, leak_context_edge); 257 return; 258 } 259 260 const Edge* current = chain->parent(); 261 assert(current != NULL, "invariant"); 262 StoredEdge* previous = leak_context_edge; 263 264 // a leak context is the sequence of (limited) edges reachable from the leak candidate 265 if (put_edges(&previous, ¤t, EdgeUtils::leak_context)) { 266 // complete 267 assert(previous != NULL, "invariant"); 268 put_chain_epilogue(leak_context_edge, EdgeUtils::root(*previous)); 269 return; 270 } 271 272 const size_t distance_to_root = length > EdgeUtils::leak_context ? length - 1 - EdgeUtils::leak_context : length - 1; 273 assert(current->distance_to_root() == distance_to_root, "invariant"); 274 275 // a skip edge is the logical link 276 // connecting the leak context sequence with the root context sequence 277 if (put_skip_edge(&previous, ¤t, distance_to_root)) { 278 // complete 279 assert(previous != NULL, "invariant"); 280 assert(previous->is_skip_edge(), "invariant"); 281 assert(previous->parent() != NULL, "invariant"); 282 put_chain_epilogue(leak_context_edge, EdgeUtils::root(*previous->parent())); 283 return; 284 } 285 286 assert(current->distance_to_root() < EdgeUtils::root_context, "invariant"); 287 288 // a root context is the sequence of (limited) edges reachable from the root 289 put_edges(&previous, ¤t, EdgeUtils::root_context); 290 assert(previous != NULL, "invariant"); 291 put_chain_epilogue(leak_context_edge, EdgeUtils::root(*previous)); 292 } 293 294 void EdgeStore::put_chain_epilogue(StoredEdge* leak_context_edge, const Edge* root) const { 295 assert(leak_context_edge != NULL, "invariant"); 296 assert(root != NULL, "invariant"); 297 store_gc_root_id_in_leak_context_edge(leak_context_edge, root); 298 assert(leak_context_edge->distance_to_root() + 1 <= EdgeUtils::max_ref_chain_depth, "invariant"); 299 } 300 301 // To avoid another traversal to resolve the root edge id later, 302 // cache it in the immediate leak context edge for fast retrieval. 303 void EdgeStore::store_gc_root_id_in_leak_context_edge(StoredEdge* leak_context_edge, const Edge* root) const { 304 assert(leak_context_edge != NULL, "invariant"); 305 assert(leak_context_edge->gc_root_id() == 0, "invariant"); 306 assert(root != NULL, "invariant"); 307 assert(root->parent() == NULL, "invariant"); 308 assert(root->distance_to_root() == 0, "invariant"); 309 const StoredEdge* const stored_root = static_cast<const StoredEdge*>(root); 310 traceid root_id = stored_root->gc_root_id(); 311 if (root_id == 0) { 312 root_id = get_id(root); 313 stored_root->set_gc_root_id(root_id); 314 } 315 assert(root_id != 0, "invariant"); 316 leak_context_edge->set_gc_root_id(root_id); 317 assert(leak_context_edge->gc_root_id() == stored_root->gc_root_id(), "invariant"); 318 }