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   int loop_count = 0;
  73   int loop_max = MaxJavaStackTraceDepth * 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   MutexLockerEx 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   MutexLockerEx 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   return instance().add_trace(stacktrace);
 168 }
 169 
 170 traceid JfrStackTraceRepository::record(Thread* thread, int skip /* 0 */) {
 171   assert(thread == Thread::current(), "invariant");
 172   JfrThreadLocal* const tl = thread->jfr_thread_local();
 173   assert(tl != NULL, "invariant");
 174   if (tl->has_cached_stack_trace()) {
 175     return tl->cached_stack_trace_id();
 176   }
 177   if (!thread->is_Java_thread() || thread->is_hidden_from_external_view()) {
 178     return 0;
 179   }
 180   JfrStackFrame* frames = tl->stackframes();
 181   if (frames == NULL) {
 182     // pending oom
 183     return 0;
 184   }
 185   assert(frames != NULL, "invariant");
 186   assert(tl->stackframes() == frames, "invariant");
 187   return instance().record_for((JavaThread*)thread, skip,frames, tl->stackdepth());
 188 }
 189 
 190 traceid JfrStackTraceRepository::record(Thread* thread, int skip, unsigned int* hash) {
 191   assert(thread == Thread::current(), "invariant");
 192   JfrThreadLocal* const tl = thread->jfr_thread_local();
 193   assert(tl != NULL, "invariant");
 194 
 195   if (tl->has_cached_stack_trace()) {
 196     *hash = tl->cached_stack_trace_hash();
 197     return tl->cached_stack_trace_id();
 198   }
 199   if (!thread->is_Java_thread() || thread->is_hidden_from_external_view()) {
 200     return 0;
 201   }
 202   JfrStackFrame* frames = tl->stackframes();
 203   if (frames == NULL) {
 204     // pending oom
 205     return 0;
 206   }
 207   assert(frames != NULL, "invariant");
 208   assert(tl->stackframes() == frames, "invariant");
 209   return instance().record_for((JavaThread*)thread, skip, frames, tl->stackdepth(), hash);
 210 }
 211 
 212 traceid JfrStackTraceRepository::record_for(JavaThread* thread, int skip, JfrStackFrame *frames, u4 max_frames) {
 213   JfrStackTrace stacktrace(frames, max_frames);
 214   if (!stacktrace.record_safe(thread, skip)) {
 215     return 0;
 216   }
 217   traceid tid = add(stacktrace);
 218   if (tid == 0) {
 219     stacktrace.resolve_linenos();
 220     tid = add(stacktrace);
 221   }
 222   return tid;
 223 }
 224 
 225 traceid JfrStackTraceRepository::record_for(JavaThread* thread, int skip, JfrStackFrame *frames, u4 max_frames, unsigned int* hash) {
 226   assert(hash != NULL && *hash == 0, "invariant");
 227   JfrStackTrace stacktrace(frames, max_frames);
 228   if (!stacktrace.record_safe(thread, skip, true)) {
 229     return 0;
 230   }
 231   traceid tid = add(stacktrace);
 232   if (tid == 0) {
 233     stacktrace.resolve_linenos();
 234     tid = add(stacktrace);
 235   }
 236   *hash = stacktrace._hash;
 237   return tid;
 238 }
 239 
 240 size_t JfrStackTraceRepository::write_impl(JfrChunkWriter& sw, bool clear) {
 241   MutexLockerEx lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
 242   assert(_entries > 0, "invariant");
 243   int count = 0;
 244   for (u4 i = 0; i < TABLE_SIZE; ++i) {
 245     JfrStackTraceRepository::StackTrace* stacktrace = _table[i];
 246     while (stacktrace != NULL) {
 247       JfrStackTraceRepository::StackTrace* next = stacktrace->next();
 248       if (stacktrace->should_write()) {
 249         stacktrace->write(sw);
 250         ++count;
 251       }
 252       if (clear) {
 253         delete stacktrace;
 254       }
 255       stacktrace = next;
 256     }
 257   }
 258   if (clear) {
 259     memset(_table, 0, sizeof(_table));
 260     _entries = 0;
 261   }
 262   return count;
 263 }
 264 
 265 size_t JfrStackTraceRepository::write(JfrChunkWriter& sw, bool clear) {
 266   return _entries > 0 ? write_impl(sw, clear) : 0;
 267 }
 268 
 269 traceid JfrStackTraceRepository::write(JfrCheckpointWriter& writer, traceid id, unsigned int hash) {
 270   assert(JfrStacktrace_lock->owned_by_self(), "invariant");
 271   const StackTrace* const trace = resolve_entry(hash, id);
 272   assert(trace != NULL, "invariant");
 273   assert(trace->hash() == hash, "invariant");
 274   assert(trace->id() == id, "invariant");
 275   trace->write(writer);
 276   return id;
 277 }
 278 
 279 JfrStackTraceRepository::StackTrace::StackTrace(traceid id, const JfrStackTrace& trace, JfrStackTraceRepository::StackTrace* next) :
 280   _next(next),
 281   _frames(NULL),
 282   _id(id),
 283   _nr_of_frames(trace._nr_of_frames),
 284   _hash(trace._hash),
 285   _reached_root(trace._reached_root),
 286   _written(false) {
 287   if (_nr_of_frames > 0) {
 288     _frames = NEW_C_HEAP_ARRAY(JfrStackFrame, _nr_of_frames, mtTracing);
 289     memcpy(_frames, trace._frames, _nr_of_frames * sizeof(JfrStackFrame));
 290   }
 291 }
 292 
 293 JfrStackTraceRepository::StackTrace::~StackTrace() {
 294   if (_frames != NULL) {
 295     FREE_C_HEAP_ARRAY(JfrStackFrame, _frames);
 296   }
 297 }
 298 
 299 bool JfrStackTraceRepository::StackTrace::equals(const JfrStackTrace& rhs) const {
 300   if (_reached_root != rhs._reached_root || _nr_of_frames != rhs._nr_of_frames || _hash != rhs._hash) {
 301     return false;
 302   }
 303   for (u4 i = 0; i < _nr_of_frames; ++i) {
 304     if (!_frames[i].equals(rhs._frames[i])) {
 305       return false;
 306     }
 307   }
 308   return true;
 309 }
 310 
 311 template <typename Writer>
 312 static void write_stacktrace(Writer& w, traceid id, bool reached_root, u4 nr_of_frames, const JfrStackFrame* frames) {
 313   w.write((u8)id);
 314   w.write((u1)!reached_root);
 315   w.write(nr_of_frames);
 316   for (u4 i = 0; i < nr_of_frames; ++i) {
 317     frames[i].write(w);
 318   }
 319 }
 320 
 321 void JfrStackTraceRepository::StackTrace::write(JfrChunkWriter& sw) const {
 322   assert(!_written, "invariant");
 323   write_stacktrace(sw, _id, _reached_root, _nr_of_frames, _frames);
 324   _written = true;
 325 }
 326 
 327 void JfrStackTraceRepository::StackTrace::write(JfrCheckpointWriter& cpw) const {
 328   write_stacktrace(cpw, _id, _reached_root, _nr_of_frames, _frames);
 329 }
 330 
 331 // JfrStackFrame
 332 
 333 bool JfrStackFrame::equals(const JfrStackFrame& rhs) const {
 334   return _methodid == rhs._methodid && _bci == rhs._bci && _type == rhs._type;
 335 }
 336 
 337 template <typename Writer>
 338 static void write_frame(Writer& w, traceid methodid, int line, int bci, u1 type) {
 339   w.write((u8)methodid);
 340   w.write((u4)line);
 341   w.write((u4)bci);
 342   w.write((u8)type);
 343 }
 344 
 345 void JfrStackFrame::write(JfrChunkWriter& cw) const {
 346   write_frame(cw, _methodid, _line, _bci, _type);
 347 }
 348 
 349 void JfrStackFrame::write(JfrCheckpointWriter& cpw) const {
 350   write_frame(cpw, _methodid, _line, _bci, _type);
 351 }
 352 
 353 // invariant is that the entry to be resolved actually exists in the table
 354 const JfrStackTraceRepository::StackTrace* JfrStackTraceRepository::resolve_entry(unsigned int hash, traceid id) const {
 355   const size_t index = (hash % TABLE_SIZE);
 356   const StackTrace* trace = _table[index];
 357   while (trace != NULL && trace->id() != id) {
 358     trace = trace->next();
 359   }
 360   assert(trace != NULL, "invariant");
 361   assert(trace->hash() == hash, "invariant");
 362   assert(trace->id() == id, "invariant");
 363   return trace;
 364 }
 365 
 366 void JfrStackFrame::resolve_lineno() {
 367   assert(_method, "no method pointer");
 368   assert(_line == 0, "already have linenumber");
 369   _line = _method->line_number_from_bci(_bci);
 370   _method = NULL;
 371 }
 372 
 373 void JfrStackTrace::set_frame(u4 frame_pos, JfrStackFrame& frame) {
 374   assert(frame_pos < _max_frames, "illegal frame_pos");
 375   _frames[frame_pos] = frame;
 376 }
 377 
 378 void JfrStackTrace::resolve_linenos() {
 379   for(unsigned int i = 0; i < _nr_of_frames; i++) {
 380     _frames[i].resolve_lineno();
 381   }
 382   _lineno = true;
 383 }
 384 
 385 bool JfrStackTrace::record_safe(JavaThread* thread, int skip, bool leakp /* false */) {
 386   assert(thread == Thread::current(), "Thread stack needs to be walkable");
 387   vframeStream vfs(thread);
 388   u4 count = 0;
 389   _reached_root = true;
 390   for(int i = 0; i < skip; i++) {
 391     if (vfs.at_end()) {
 392       break;
 393     }
 394     vfs.next();
 395   }
 396 
 397   while (!vfs.at_end()) {
 398     if (count >= _max_frames) {
 399       _reached_root = false;
 400       break;
 401     }
 402     const Method* method = vfs.method();
 403     const traceid mid = JfrTraceId::use(method, leakp);
 404     int type = vfs.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
 405     int bci = 0;
 406     if (method->is_native()) {
 407       type = JfrStackFrame::FRAME_NATIVE;
 408     } else {
 409       bci = vfs.bci();
 410     }
 411     // Can we determine if it's inlined?
 412     _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
 413     _frames[count] = JfrStackFrame(mid, bci, type, method);
 414     vfs.next();
 415     count++;
 416   }
 417 
 418   _nr_of_frames = count;
 419   return true;
 420 }
 421 
 422 bool JfrStackTrace::record_thread(JavaThread& thread, frame& frame) {
 423   vframeStreamSamples st(&thread, frame, false);
 424   u4 count = 0;
 425   _reached_root = true;
 426 
 427   while (!st.at_end()) {
 428     if (count >= _max_frames) {
 429       _reached_root = false;
 430       break;
 431     }
 432     const Method* method = st.method();
 433     if (!Method::is_valid_method(method)) {
 434       // we throw away everything we've gathered in this sample since
 435       // none of it is safe
 436       return false;
 437     }
 438     const traceid mid = JfrTraceId::use(method);
 439     int type = st.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
 440     int bci = 0;
 441     if (method->is_native()) {
 442       type = JfrStackFrame::FRAME_NATIVE;
 443     } else {
 444       bci = st.bci();
 445     }
 446     const int lineno = method->line_number_from_bci(bci);
 447     // Can we determine if it's inlined?
 448     _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
 449     _frames[count] = JfrStackFrame(mid, bci, type, lineno);
 450     st.samples_next();
 451     count++;
 452   }
 453 
 454   _lineno = true;
 455   _nr_of_frames = count;
 456   return true;
 457 }
 458 
 459 void JfrStackTraceRepository::write_metadata(JfrCheckpointWriter& writer) {
 460   JfrFrameType fct;
 461   writer.write_type(TYPE_FRAMETYPE);
 462   fct.serialize(writer);
 463 }
--- EOF ---