1 /*
  2  * Copyright (c) 2011, 2019, 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/metadata/jfrSerializer.hpp"
 27 #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
 28 #include "jfr/recorder/repository/jfrChunkWriter.hpp"
 29 #include "jfr/recorder/service/jfrOptionSet.hpp"
 30 #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
 31 #include "jfr/utilities/jfrTypes.hpp"
 32 #include "memory/allocation.inline.hpp"
 33 #include "runtime/mutexLocker.hpp"
 34 #include "runtime/os.inline.hpp"
 35 #include "runtime/safepoint.hpp"
 36 #include "runtime/task.hpp"
 37 #include "runtime/vframe.inline.hpp"
 38 
 39 class vframeStreamSamples : public vframeStreamCommon {
 40  public:
 41   // constructor that starts with sender of frame fr (top_frame)
 42   vframeStreamSamples(JavaThread *jt, frame fr, bool stop_at_java_call_stub);
 43   void samples_next();
 44   void stop() {}
 45 };
 46 
 47 vframeStreamSamples::vframeStreamSamples(JavaThread *jt, frame fr, bool stop_at_java_call_stub) : vframeStreamCommon(jt) {
 48   _stop_at_java_call_stub = stop_at_java_call_stub;
 49   _frame = fr;
 50 
 51   // We must always have a valid frame to start filling
 52   bool filled_in = fill_from_frame();
 53   assert(filled_in, "invariant");
 54 }
 55 
 56 // Solaris SPARC Compiler1 needs an additional check on the grandparent
 57 // of the top_frame when the parent of the top_frame is interpreted and
 58 // the grandparent is compiled. However, in this method we do not know
 59 // the relationship of the current _frame relative to the top_frame so
 60 // we implement a more broad sanity check. When the previous callee is
 61 // interpreted and the current sender is compiled, we verify that the
 62 // current sender is also walkable. If it is not walkable, then we mark
 63 // the current vframeStream as at the end.
 64 void vframeStreamSamples::samples_next() {
 65   // handle frames with inlining
 66   if (_mode == compiled_mode &&
 67       vframeStreamCommon::fill_in_compiled_inlined_sender()) {
 68     return;
 69   }
 70 
 71   // handle general case
 72   u4 loop_count = 0;
 73   u4 loop_max = MAX_STACK_DEPTH * 2;
 74   do {
 75     loop_count++;
 76     // By the time we get here we should never see unsafe but better safe then segv'd
 77     if (loop_count > loop_max || !_frame.safe_for_sender(_thread)) {
 78       _mode = at_end_mode;
 79       return;
 80     }
 81     _frame = _frame.sender(&_reg_map);
 82   } while (!fill_from_frame());
 83 }
 84 
 85 static JfrStackTraceRepository* _instance = NULL;
 86 
 87 JfrStackTraceRepository& JfrStackTraceRepository::instance() {
 88   return *_instance;
 89 }
 90 
 91 JfrStackTraceRepository* JfrStackTraceRepository::create() {
 92   assert(_instance == NULL, "invariant");
 93   _instance = new JfrStackTraceRepository();
 94   return _instance;
 95 }
 96 
 97 void JfrStackTraceRepository::destroy() {
 98   assert(_instance != NULL, "invarinat");
 99   delete _instance;
100   _instance = NULL;
101 }
102 
103 JfrStackTraceRepository::JfrStackTraceRepository() : _next_id(0), _entries(0) {
104   memset(_table, 0, sizeof(_table));
105 }
106 class JfrFrameType : public JfrSerializer {
107  public:
108   void serialize(JfrCheckpointWriter& writer) {
109     writer.write_count(JfrStackFrame::NUM_FRAME_TYPES);
110     writer.write_key(JfrStackFrame::FRAME_INTERPRETER);
111     writer.write("Interpreted");
112     writer.write_key(JfrStackFrame::FRAME_JIT);
113     writer.write("JIT compiled");
114     writer.write_key(JfrStackFrame::FRAME_INLINE);
115     writer.write("Inlined");
116     writer.write_key(JfrStackFrame::FRAME_NATIVE);
117     writer.write("Native");
118   }
119 };
120 
121 bool JfrStackTraceRepository::initialize() {
122   return JfrSerializer::register_serializer(TYPE_FRAMETYPE, false, true, new JfrFrameType());
123 }
124 
125 size_t JfrStackTraceRepository::clear() {
126   MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
127   if (_entries == 0) {
128     return 0;
129   }
130   for (u4 i = 0; i < TABLE_SIZE; ++i) {
131     JfrStackTraceRepository::StackTrace* stacktrace = _table[i];
132     while (stacktrace != NULL) {
133       JfrStackTraceRepository::StackTrace* next = stacktrace->next();
134       delete stacktrace;
135       stacktrace = next;
136     }
137   }
138   memset(_table, 0, sizeof(_table));
139   const size_t processed = _entries;
140   _entries = 0;
141   return processed;
142 }
143 
144 traceid JfrStackTraceRepository::add_trace(const JfrStackTrace& stacktrace) {
145   MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
146   const size_t index = stacktrace._hash % TABLE_SIZE;
147   const StackTrace* table_entry = _table[index];
148 
149   while (table_entry != NULL) {
150     if (table_entry->equals(stacktrace)) {
151       return table_entry->id();
152     }
153     table_entry = table_entry->next();
154   }
155 
156   if (!stacktrace.have_lineno()) {
157     return 0;
158   }
159 
160   traceid id = ++_next_id;
161   _table[index] = new StackTrace(id, stacktrace, _table[index]);
162   ++_entries;
163   return id;
164 }
165 
166 traceid JfrStackTraceRepository::add(const JfrStackTrace& stacktrace) {
167   traceid tid = instance().add_trace(stacktrace);
168   if (tid == 0) {
169     stacktrace.resolve_linenos();
170     tid = instance().add_trace(stacktrace);
171   }
172   assert(tid != 0, "invariant");
173   return tid;
174 }
175 
176 traceid JfrStackTraceRepository::record(Thread* thread, int skip /* 0 */) {
177   assert(thread == Thread::current(), "invariant");
178   JfrThreadLocal* const tl = thread->jfr_thread_local();
179   assert(tl != NULL, "invariant");
180   if (tl->has_cached_stack_trace()) {
181     return tl->cached_stack_trace_id();
182   }
183   if (!thread->is_Java_thread() || thread->is_hidden_from_external_view()) {
184     return 0;
185   }
186   JfrStackFrame* frames = tl->stackframes();
187   if (frames == NULL) {
188     // pending oom
189     return 0;
190   }
191   assert(frames != NULL, "invariant");
192   assert(tl->stackframes() == frames, "invariant");
193   return instance().record_for((JavaThread*)thread, skip,frames, tl->stackdepth());
194 }
195 
196 traceid JfrStackTraceRepository::record_for(JavaThread* thread, int skip, JfrStackFrame *frames, u4 max_frames) {
197   JfrStackTrace stacktrace(frames, max_frames);
198   return stacktrace.record_safe(thread, skip) ? add(stacktrace) : 0;
199 }
200 
201 traceid JfrStackTraceRepository::add(const JfrStackTrace* stacktrace, JavaThread* thread) {
202   assert(stacktrace != NULL, "invariant");
203   assert(thread != NULL, "invariant");
204   assert(stacktrace->hash() != 0, "invariant");
205   return add(*stacktrace);
206 }
207 
208 bool JfrStackTraceRepository::fill_stacktrace_for(JavaThread* thread, JfrStackTrace* stacktrace, int skip) {
209   assert(thread == Thread::current(), "invariant");
210   assert(stacktrace != NULL, "invariant");
211   JfrThreadLocal* const tl = thread->jfr_thread_local();
212   assert(tl != NULL, "invariant");
213   const unsigned int cached_stacktrace_hash = tl->cached_stack_trace_hash();
214   if (cached_stacktrace_hash != 0) {
215     stacktrace->set_hash(cached_stacktrace_hash);
216     return true;
217   }
218   return stacktrace->record_safe(thread, skip, true);
219 }
220 
221 size_t JfrStackTraceRepository::write_impl(JfrChunkWriter& sw, bool clear) {
222   MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
223   assert(_entries > 0, "invariant");
224   int count = 0;
225   for (u4 i = 0; i < TABLE_SIZE; ++i) {
226     JfrStackTraceRepository::StackTrace* stacktrace = _table[i];
227     while (stacktrace != NULL) {
228       JfrStackTraceRepository::StackTrace* next = stacktrace->next();
229       if (stacktrace->should_write()) {
230         stacktrace->write(sw);
231         ++count;
232       }
233       if (clear) {
234         delete stacktrace;
235       }
236       stacktrace = next;
237     }
238   }
239   if (clear) {
240     memset(_table, 0, sizeof(_table));
241     _entries = 0;
242   }
243   return count;
244 }
245 
246 size_t JfrStackTraceRepository::write(JfrChunkWriter& sw, bool clear) {
247   return _entries > 0 ? write_impl(sw, clear) : 0;
248 }
249 
250 traceid JfrStackTraceRepository::write(JfrCheckpointWriter& writer, traceid id, unsigned int hash) {
251   assert(JfrStacktrace_lock->owned_by_self(), "invariant");
252   const StackTrace* const trace = resolve_entry(hash, id);
253   assert(trace != NULL, "invariant");
254   assert(trace->hash() == hash, "invariant");
255   assert(trace->id() == id, "invariant");
256   trace->write(writer);
257   return id;
258 }
259 
260 JfrStackTraceRepository::StackTrace::StackTrace(traceid id, const JfrStackTrace& trace, JfrStackTraceRepository::StackTrace* next) :
261   _next(next),
262   _frames(NULL),
263   _id(id),
264   _nr_of_frames(trace._nr_of_frames),
265   _hash(trace._hash),
266   _reached_root(trace._reached_root),
267   _written(false) {
268   if (_nr_of_frames > 0) {
269     _frames = NEW_C_HEAP_ARRAY(JfrStackFrame, _nr_of_frames, mtTracing);
270     memcpy(_frames, trace._frames, _nr_of_frames * sizeof(JfrStackFrame));
271   }
272 }
273 
274 JfrStackTraceRepository::StackTrace::~StackTrace() {
275   if (_frames != NULL) {
276     FREE_C_HEAP_ARRAY(JfrStackFrame, _frames);
277   }
278 }
279 
280 bool JfrStackTraceRepository::StackTrace::equals(const JfrStackTrace& rhs) const {
281   if (_reached_root != rhs._reached_root || _nr_of_frames != rhs._nr_of_frames || _hash != rhs._hash) {
282     return false;
283   }
284   for (u4 i = 0; i < _nr_of_frames; ++i) {
285     if (!_frames[i].equals(rhs._frames[i])) {
286       return false;
287     }
288   }
289   return true;
290 }
291 
292 template <typename Writer>
293 static void write_stacktrace(Writer& w, traceid id, bool reached_root, u4 nr_of_frames, const JfrStackFrame* frames) {
294   w.write((u8)id);
295   w.write((u1)!reached_root);
296   w.write(nr_of_frames);
297   for (u4 i = 0; i < nr_of_frames; ++i) {
298     frames[i].write(w);
299   }
300 }
301 
302 void JfrStackTraceRepository::StackTrace::write(JfrChunkWriter& sw) const {
303   assert(!_written, "invariant");
304   write_stacktrace(sw, _id, _reached_root, _nr_of_frames, _frames);
305   _written = true;
306 }
307 
308 void JfrStackTraceRepository::StackTrace::write(JfrCheckpointWriter& cpw) const {
309   write_stacktrace(cpw, _id, _reached_root, _nr_of_frames, _frames);
310 }
311 
312 // JfrStackFrame
313 
314 bool JfrStackFrame::equals(const JfrStackFrame& rhs) const {
315   return _methodid == rhs._methodid && _bci == rhs._bci && _type == rhs._type;
316 }
317 
318 template <typename Writer>
319 static void write_frame(Writer& w, traceid methodid, int line, int bci, u1 type) {
320   w.write((u8)methodid);
321   w.write((u4)line);
322   w.write((u4)bci);
323   w.write((u8)type);
324 }
325 
326 void JfrStackFrame::write(JfrChunkWriter& cw) const {
327   write_frame(cw, _methodid, _line, _bci, _type);
328 }
329 
330 void JfrStackFrame::write(JfrCheckpointWriter& cpw) const {
331   write_frame(cpw, _methodid, _line, _bci, _type);
332 }
333 
334 // invariant is that the entry to be resolved actually exists in the table
335 const JfrStackTraceRepository::StackTrace* JfrStackTraceRepository::resolve_entry(unsigned int hash, traceid id) const {
336   const size_t index = (hash % TABLE_SIZE);
337   const StackTrace* trace = _table[index];
338   while (trace != NULL && trace->id() != id) {
339     trace = trace->next();
340   }
341   assert(trace != NULL, "invariant");
342   assert(trace->hash() == hash, "invariant");
343   assert(trace->id() == id, "invariant");
344   return trace;
345 }
346 
347 void JfrStackFrame::resolve_lineno() const {
348   assert(_method, "no method pointer");
349   assert(_line == 0, "already have linenumber");
350   _line = _method->line_number_from_bci(_bci);
351   _method = NULL;
352 }
353 
354 void JfrStackTrace::set_frame(u4 frame_pos, JfrStackFrame& frame) {
355   assert(frame_pos < _max_frames, "illegal frame_pos");
356   _frames[frame_pos] = frame;
357 }
358 
359 void JfrStackTrace::resolve_linenos() const {
360   for(unsigned int i = 0; i < _nr_of_frames; i++) {
361     _frames[i].resolve_lineno();
362   }
363   _lineno = true;
364 }
365 
366 bool JfrStackTrace::record_safe(JavaThread* thread, int skip, bool leakp /* false */) {
367   assert(thread == Thread::current(), "Thread stack needs to be walkable");
368   vframeStream vfs(thread);
369   u4 count = 0;
370   _reached_root = true;
371   for(int i = 0; i < skip; i++) {
372     if (vfs.at_end()) {
373       break;
374     }
375     vfs.next();
376   }
377 
378   while (!vfs.at_end()) {
379     if (count >= _max_frames) {
380       _reached_root = false;
381       break;
382     }
383     const Method* method = vfs.method();
384     const traceid mid = JfrTraceId::use(method, leakp);
385     int type = vfs.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
386     int bci = 0;
387     if (method->is_native()) {
388       type = JfrStackFrame::FRAME_NATIVE;
389     } else {
390       bci = vfs.bci();
391     }
392     // Can we determine if it's inlined?
393     _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
394     _frames[count] = JfrStackFrame(mid, bci, type, method);
395     vfs.next();
396     count++;
397   }
398 
399   _nr_of_frames = count;
400   return true;
401 }
402 
403 bool JfrStackTrace::record_thread(JavaThread& thread, frame& frame) {
404   vframeStreamSamples st(&thread, frame, false);
405   u4 count = 0;
406   _reached_root = true;
407 
408   while (!st.at_end()) {
409     if (count >= _max_frames) {
410       _reached_root = false;
411       break;
412     }
413     const Method* method = st.method();
414     if (!Method::is_valid_method(method)) {
415       // we throw away everything we've gathered in this sample since
416       // none of it is safe
417       return false;
418     }
419     const traceid mid = JfrTraceId::use(method);
420     int type = st.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
421     int bci = 0;
422     if (method->is_native()) {
423       type = JfrStackFrame::FRAME_NATIVE;
424     } else {
425       bci = st.bci();
426     }
427     const int lineno = method->line_number_from_bci(bci);
428     // Can we determine if it's inlined?
429     _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
430     _frames[count] = JfrStackFrame(mid, bci, type, lineno);
431     st.samples_next();
432     count++;
433   }
434 
435   _lineno = true;
436   _nr_of_frames = count;
437   return true;
438 }
439 
440 void JfrStackTraceRepository::write_metadata(JfrCheckpointWriter& writer) {
441   JfrFrameType fct;
442   writer.write_type(TYPE_FRAMETYPE);
443   fct.serialize(writer);
444 }