< prev index next >

src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp

Print this page
@@ -1,7 +1,7 @@
  /*
-  * 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.

@@ -23,30 +23,23 @@
   */
  
  #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) {

@@ -222,19 +215,95 @@
      ++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 >