1 /*
   2  * Copyright (c) 2014, 2018, 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 #ifndef SHARE_VM_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP
  26 #define SHARE_VM_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP
  27 
  28 #include "jfr/recorder/checkpoint/jfrCheckpointBlob.hpp"
  29 #include "jfr/utilities/jfrAllocation.hpp"
  30 #include "jfr/utilities/jfrTraceTime.hpp"
  31 #include "memory/allocation.hpp"
  32 #include "oops/oop.hpp"
  33 #include "trace/tracing.hpp"
  34 #include "utilities/ticks.hpp"
  35 /*
  36  * Handle for diagnosing Java memory leaks.
  37  *
  38  * The class tracks the time the object was
  39  * allocated, the thread and the stack trace.
  40  */
  41 class ObjectSample : public JfrCHeapObj {
  42   friend class ObjectSampler;
  43   friend class SampleList;
  44  private:
  45   ObjectSample* _next;
  46   ObjectSample* _previous;
  47   JfrCheckpointBlobHandle _thread_cp;
  48   JfrCheckpointBlobHandle _klass_cp;
  49   oop _object;
  50   Ticks _allocation_time;
  51   traceid _stack_trace_id;
  52   traceid _thread_id;
  53   int _index;
  54   size_t _span;
  55   size_t _allocated;
  56   unsigned int _stack_trace_hash;
  57   bool _dead;
  58 
  59   void set_dead() {
  60     _dead = true;
  61   }
  62 
  63   void release_references() {
  64     if (_thread_cp.valid()) {
  65       _thread_cp.~JfrCheckpointBlobHandle();
  66     }
  67     if (_klass_cp.valid()) {
  68       _klass_cp.~JfrCheckpointBlobHandle();
  69     }
  70   }
  71 
  72   void reset() {
  73     set_stack_trace_id(0);
  74     set_stack_trace_hash(0),
  75     release_references();
  76     _dead = false;
  77   }
  78 
  79  public:
  80   ObjectSample() : _next(NULL),
  81                    _previous(NULL),
  82                    _thread_cp(),
  83                    _klass_cp(),
  84                    _object(NULL),
  85                    _allocation_time(0),
  86                    _stack_trace_id(0),
  87                    _thread_id(0),
  88                    _index(0),
  89                    _span(0),
  90                    _allocated(0),
  91                    _stack_trace_hash(0),
  92                    _dead(false) {}
  93 
  94   ObjectSample* next() const {
  95     return _next;
  96   }
  97 
  98   void set_next(ObjectSample* next) {
  99     _next = next;
 100   }
 101 
 102   ObjectSample* prev() const {
 103     return _previous;
 104   }
 105 
 106   void set_prev(ObjectSample* prev) {
 107     _previous = prev;
 108   }
 109 
 110   bool is_dead() const {
 111     return _dead;
 112   }
 113 
 114   const oop object() const {
 115     return _object;
 116   }
 117 
 118   const oop* object_addr() const {
 119     return &_object;
 120   }
 121 
 122   void set_object(oop object) {
 123     _object = object;
 124   }
 125 
 126   const Klass* klass() const {
 127     assert(_object != NULL, "invariant");
 128     return _object->klass();
 129   }
 130 
 131   int index() const {
 132     return _index;
 133   }
 134 
 135   void set_index(int index) {
 136     _index = index;
 137   }
 138 
 139   size_t span() const {
 140     return _span;
 141   }
 142 
 143   void set_span(size_t span) {
 144     _span = span;
 145   }
 146 
 147   void add_span(size_t span) {
 148     _span += span;
 149   }
 150 
 151   size_t allocated() const {
 152     return _allocated;
 153   }
 154 
 155   void set_allocated(size_t size) {
 156     _allocated = size;
 157   }
 158 
 159   const Ticks& allocation_time() const {
 160     return _allocation_time;
 161   }
 162 
 163   const void set_allocation_time(const JfrTraceTime& time) {
 164     _allocation_time = Ticks(time.value());
 165   }
 166 
 167   bool has_stack_trace() const {
 168     return stack_trace_id() != 0;
 169   }
 170 
 171   traceid stack_trace_id() const {
 172     return _stack_trace_id;
 173   }
 174 
 175   void set_stack_trace_id(traceid id) {
 176     _stack_trace_id = id;
 177   }
 178 
 179   unsigned int stack_trace_hash() const {
 180     return _stack_trace_hash;
 181   }
 182 
 183   void set_stack_trace_hash(unsigned int hash) {
 184     _stack_trace_hash = hash;
 185   }
 186 
 187   bool has_thread() const {
 188     return _thread_id != 0;
 189   }
 190 
 191   traceid thread_id() const {
 192     return _thread_id;
 193   }
 194 
 195   void set_thread_id(traceid id) {
 196     _thread_id = id;
 197   }
 198 
 199   bool is_alive_and_older_than(jlong time_stamp) const {
 200     return !is_dead() && (JfrTraceTime::is_ft_enabled() ?
 201       _allocation_time.ft_value() : _allocation_time.value()) < time_stamp;
 202   }
 203 
 204   const JfrCheckpointBlobHandle& thread_checkpoint() const {
 205     return _thread_cp;
 206   }
 207 
 208   bool has_thread_checkpoint() const {
 209     return _thread_cp.valid();
 210   }
 211 
 212   // JfrCheckpointBlobHandle assignment operator
 213   // maintains proper reference counting
 214   void set_thread_checkpoint(const JfrCheckpointBlobHandle& ref) {
 215     if (_thread_cp != ref) {
 216       _thread_cp = ref;
 217     }
 218   }
 219 
 220   const JfrCheckpointBlobHandle& klass_checkpoint() const {
 221     return _klass_cp;
 222   }
 223 
 224   bool has_klass_checkpoint() const {
 225     return _klass_cp.valid();
 226   }
 227 
 228   void set_klass_checkpoint(const JfrCheckpointBlobHandle& ref) {
 229     if (_klass_cp != ref) {
 230       if (_klass_cp.valid()) {
 231         _klass_cp->set_next(ref);
 232         return;
 233       }
 234       _klass_cp = ref;
 235     }
 236   }
 237 };
 238 
 239 #endif // SHARE_VM_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP