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