< prev index next > src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp
Print this page
/*
- * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*/
#include "precompiled.hpp"
#include "jfr/leakprofiler/chains/edgeStore.hpp"
#include "jfr/leakprofiler/chains/edgeUtils.hpp"
+ #include "jfr/leakprofiler/sampling/objectSample.hpp"
#include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp"
#include "oops/oop.inline.hpp"
+ #include "runtime/safepoint.hpp"
StoredEdge::StoredEdge(const Edge* parent, UnifiedOopRef reference) : Edge(parent, reference), _gc_root_id(0), _skip_length(0) {}
StoredEdge::StoredEdge(const Edge& edge) : Edge(edge), _gc_root_id(0), _skip_length(0) {}
StoredEdge::StoredEdge(const StoredEdge& edge) : Edge(edge), _gc_root_id(edge._gc_root_id), _skip_length(edge._skip_length) {}
traceid EdgeStore::_edge_id_counter = 0;
- EdgeStore::EdgeStore() : _edges(NULL) {
- _edges = new EdgeHashTable(this);
- }
-
- EdgeStore::~EdgeStore() {
- assert(_edges != NULL, "invariant");
- delete _edges;
- }
-
bool EdgeStore::is_empty() const {
return !_edges->has_entries();
}
void EdgeStore::on_link(EdgeEntry* entry) {
++depth;
}
return NULL == *current;
}
- // Install the immediate edge into the mark word of the leak candidate object
+ static GrowableArray<const StoredEdge*>* _leak_context_edges = nullptr;
+
+ EdgeStore::EdgeStore() : _edges(new EdgeHashTable(this)) {}
+
+ EdgeStore::~EdgeStore() {
+ assert(_edges != NULL, "invariant");
+ delete _edges;
+ delete _leak_context_edges;
+ _leak_context_edges = nullptr;
+ }
+
+ static int leak_context_edge_idx(const ObjectSample* sample) {
+ assert(sample != nullptr, "invariant");
+ return static_cast<int>(sample->object()->mark().value()) >> markWord::lock_bits;
+ }
+
+ bool EdgeStore::has_leak_context(const ObjectSample* sample) const {
+ const int idx = leak_context_edge_idx(sample);
+ if (idx == 0) {
+ return false;
+ }
+ assert(idx > 0, "invariant");
+ assert(_leak_context_edges != nullptr, "invariant");
+ assert(idx < _leak_context_edges->length(), "invariant");
+ assert(_leak_context_edges->at(idx) != nullptr, "invariant");
+ return true;
+ }
+
+ const StoredEdge* EdgeStore::get(const ObjectSample* sample) const {
+ assert(sample != nullptr, "invariant");
+ if (_leak_context_edges != nullptr) {
+ assert(SafepointSynchronize::is_at_safepoint(), "invariant");
+ const int idx = leak_context_edge_idx(sample);
+ if (idx > 0) {
+ assert(idx < _leak_context_edges->length(), "invariant");
+ const StoredEdge* const edge =_leak_context_edges->at(idx);
+ assert(edge != nullptr, "invariant");
+ return edge;
+ }
+ }
+ return get(UnifiedOopRef::encode_in_native(sample->object_addr()));
+ }
+
+ #ifdef ASSERT
+ // max_idx to ensure idx fit in lower 32-bits of markword together with lock bits.
+ static constexpr const int max_idx = right_n_bits(32 - markWord::lock_bits);
+
+ static void store_idx_precondition(oop sample_object, int idx) {
+ assert(sample_object != NULL, "invariant");
+ assert(sample_object->mark().is_marked(), "invariant");
+ assert(idx > 0, "invariant");
+ assert(idx <= max_idx, "invariant");
+ }
+ #endif
+
+ static void store_idx_in_markword(oop sample_object, int idx) {
+ DEBUG_ONLY(store_idx_precondition(sample_object, idx);)
+ const markWord idx_mark_word(sample_object->mark().value() | idx << markWord::lock_bits);
+ sample_object->set_mark(idx_mark_word);
+ assert(sample_object->mark().is_marked(), "must still be marked");
+ }
+
+ static const int initial_size = 64;
+
+ static int save(const StoredEdge* edge) {
+ assert(edge != nullptr, "invariant");
+ if (_leak_context_edges == nullptr) {
+ _leak_context_edges = new (ResourceObj::C_HEAP, mtTracing)GrowableArray<const StoredEdge*>(initial_size, mtTracing);
+ _leak_context_edges->append(nullptr); // next idx now at 1, for disambiguation in markword.
+ }
+ return _leak_context_edges->append(edge);
+ }
+
+ // We associate the leak context edge with the leak candidate object by saving the
+ // edge in an array and storing the array idx (shifted) into the markword of the candidate object.
+ static void associate_with_candidate(const StoredEdge* leak_context_edge) {
+ assert(leak_context_edge != nullptr, "invariant");
+ store_idx_in_markword(leak_context_edge->pointee(), save(leak_context_edge));
+ }
+
StoredEdge* EdgeStore::associate_leak_context_with_candidate(const Edge* edge) {
assert(edge != NULL, "invariant");
assert(!contains(edge->reference()), "invariant");
StoredEdge* const leak_context_edge = put(edge->reference());
- oop sample_object = edge->pointee();
- assert(sample_object != NULL, "invariant");
- assert(sample_object->mark().is_marked(), "invariant");
- sample_object->set_mark(markWord::from_pointer(leak_context_edge));
+ associate_with_candidate(leak_context_edge);
return leak_context_edge;
}
/*
* The purpose of put_chain() is to reify the edge sequence
< prev index next >