src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp
branchJEP-349-branch
changeset 57870 00860d9caf4d
parent 57360 5d043a159d5c
child 57872 7aa1b3d6ff8f
equal deleted inserted replaced
57862:84ef29ccac56 57870:00860d9caf4d
    22  *
    22  *
    23  */
    23  */
    24 
    24 
    25 #include "precompiled.hpp"
    25 #include "precompiled.hpp"
    26 #include "jfr/metadata/jfrSerializer.hpp"
    26 #include "jfr/metadata/jfrSerializer.hpp"
    27 #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
    27 #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
    28 #include "jfr/recorder/repository/jfrChunkWriter.hpp"
    28 #include "jfr/recorder/repository/jfrChunkWriter.hpp"
    29 #include "jfr/recorder/service/jfrOptionSet.hpp"
       
    30 #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
    29 #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
    31 #include "jfr/utilities/jfrTypes.hpp"
       
    32 #include "memory/allocation.inline.hpp"
       
    33 #include "runtime/mutexLocker.hpp"
    30 #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 
    31 
    85 static JfrStackTraceRepository* _instance = NULL;
    32 static JfrStackTraceRepository* _instance = NULL;
       
    33 
       
    34 JfrStackTraceRepository::JfrStackTraceRepository() : _next_id(0), _entries(0) {
       
    35   memset(_table, 0, sizeof(_table));
       
    36 }
    86 
    37 
    87 JfrStackTraceRepository& JfrStackTraceRepository::instance() {
    38 JfrStackTraceRepository& JfrStackTraceRepository::instance() {
    88   return *_instance;
    39   return *_instance;
    89 }
    40 }
    90 
    41 
    92   assert(_instance == NULL, "invariant");
    43   assert(_instance == NULL, "invariant");
    93   _instance = new JfrStackTraceRepository();
    44   _instance = new JfrStackTraceRepository();
    94   return _instance;
    45   return _instance;
    95 }
    46 }
    96 
    47 
    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 {
    48 class JfrFrameType : public JfrSerializer {
   107  public:
    49  public:
   108   void serialize(JfrCheckpointWriter& writer) {
    50   void serialize(JfrCheckpointWriter& writer) {
   109     writer.write_count(JfrStackFrame::NUM_FRAME_TYPES);
    51     writer.write_count(JfrStackFrame::NUM_FRAME_TYPES);
   110     writer.write_key(JfrStackFrame::FRAME_INTERPRETER);
    52     writer.write_key(JfrStackFrame::FRAME_INTERPRETER);
   120 
    62 
   121 bool JfrStackTraceRepository::initialize() {
    63 bool JfrStackTraceRepository::initialize() {
   122   return JfrSerializer::register_serializer(TYPE_FRAMETYPE, true, new JfrFrameType());
    64   return JfrSerializer::register_serializer(TYPE_FRAMETYPE, true, new JfrFrameType());
   123 }
    65 }
   124 
    66 
   125 size_t JfrStackTraceRepository::clear() {
    67 void JfrStackTraceRepository::destroy() {
   126   MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
    68   assert(_instance != NULL, "invarinat");
   127   if (_entries == 0) {
    69   delete _instance;
   128     return 0;
    70   _instance = NULL;
   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   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() || tl->is_excluded()) {
       
   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 }
    71 }
   239 
    72 
   240 size_t JfrStackTraceRepository::write_impl(JfrChunkWriter& sw, bool clear) {
    73 size_t JfrStackTraceRepository::write_impl(JfrChunkWriter& sw, bool clear) {
   241   MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
    74   MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
   242   assert(_entries > 0, "invariant");
    75   assert(_entries > 0, "invariant");
   243   int count = 0;
    76   int count = 0;
   244   for (u4 i = 0; i < TABLE_SIZE; ++i) {
    77   for (u4 i = 0; i < TABLE_SIZE; ++i) {
   245     JfrStackTraceRepository::StackTrace* stacktrace = _table[i];
    78     JfrStackTrace* stacktrace = _table[i];
   246     while (stacktrace != NULL) {
    79     while (stacktrace != NULL) {
   247       JfrStackTraceRepository::StackTrace* next = stacktrace->next();
    80       JfrStackTrace* next = const_cast<JfrStackTrace*>(stacktrace->next());
   248       if (stacktrace->should_write()) {
    81       if (stacktrace->should_write()) {
   249         stacktrace->write(sw);
    82         stacktrace->write(sw);
   250         ++count;
    83         ++count;
   251       }
    84       }
   252       if (clear) {
    85       if (clear) {
   266   return _entries > 0 ? write_impl(sw, clear) : 0;
    99   return _entries > 0 ? write_impl(sw, clear) : 0;
   267 }
   100 }
   268 
   101 
   269 traceid JfrStackTraceRepository::write(JfrCheckpointWriter& writer, traceid id, unsigned int hash) {
   102 traceid JfrStackTraceRepository::write(JfrCheckpointWriter& writer, traceid id, unsigned int hash) {
   270   assert(JfrStacktrace_lock->owned_by_self(), "invariant");
   103   assert(JfrStacktrace_lock->owned_by_self(), "invariant");
   271   const StackTrace* const trace = resolve_entry(hash, id);
   104   const JfrStackTrace* const trace = lookup(hash, id);
   272   assert(trace != NULL, "invariant");
   105   assert(trace != NULL, "invariant");
   273   assert(trace->hash() == hash, "invariant");
   106   assert(trace->hash() == hash, "invariant");
   274   assert(trace->id() == id, "invariant");
   107   assert(trace->id() == id, "invariant");
   275   trace->write(writer);
   108   trace->write(writer);
   276   return id;
   109   return id;
   277 }
   110 }
   278 
   111 
   279 JfrStackTraceRepository::StackTrace::StackTrace(traceid id, const JfrStackTrace& trace, JfrStackTraceRepository::StackTrace* next) :
   112 void JfrStackTraceRepository::write_metadata(JfrCheckpointWriter& writer) {
   280   _next(next),
   113   JfrFrameType fct;
   281   _frames(NULL),
   114   writer.write_type(TYPE_FRAMETYPE);
   282   _id(id),
   115   fct.serialize(writer);
   283   _nr_of_frames(trace._nr_of_frames),
   116 }
   284   _hash(trace._hash),
   117 
   285   _reached_root(trace._reached_root),
   118 size_t JfrStackTraceRepository::clear() {
   286   _written(false) {
   119   MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
   287   if (_nr_of_frames > 0) {
   120   if (_entries == 0) {
   288     _frames = NEW_C_HEAP_ARRAY(JfrStackFrame, _nr_of_frames, mtTracing);
   121     return 0;
   289     memcpy(_frames, trace._frames, _nr_of_frames * sizeof(JfrStackFrame));
   122   }
   290   }
   123   for (u4 i = 0; i < TABLE_SIZE; ++i) {
   291 }
   124     JfrStackTrace* stacktrace = _table[i];
   292 
   125     while (stacktrace != NULL) {
   293 JfrStackTraceRepository::StackTrace::~StackTrace() {
   126       JfrStackTrace* next = const_cast<JfrStackTrace*>(stacktrace->next());
   294   if (_frames != NULL) {
   127       delete stacktrace;
   295     FREE_C_HEAP_ARRAY(JfrStackFrame, _frames);
   128       stacktrace = next;
   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     }
   129     }
   307   }
   130   }
   308   return true;
   131   memset(_table, 0, sizeof(_table));
   309 }
   132   const size_t processed = _entries;
   310 
   133   _entries = 0;
   311 template <typename Writer>
   134   return processed;
   312 static void write_stacktrace(Writer& w, traceid id, bool reached_root, u4 nr_of_frames, const JfrStackFrame* frames) {
   135 }
   313   w.write((u8)id);
   136 
   314   w.write((u1)!reached_root);
   137 traceid JfrStackTraceRepository::record(Thread* thread, int skip /* 0 */) {
   315   w.write(nr_of_frames);
   138   assert(thread == Thread::current(), "invariant");
   316   for (u4 i = 0; i < nr_of_frames; ++i) {
   139   JfrThreadLocal* const tl = thread->jfr_thread_local();
   317     frames[i].write(w);
   140   assert(tl != NULL, "invariant");
   318   }
   141   if (tl->has_cached_stack_trace()) {
   319 }
   142     return tl->cached_stack_trace_id();
   320 
   143   }
   321 void JfrStackTraceRepository::StackTrace::write(JfrChunkWriter& sw) const {
   144   if (!thread->is_Java_thread() || thread->is_hidden_from_external_view() || tl->is_excluded()) {
   322   assert(!_written, "invariant");
   145     return 0;
   323   write_stacktrace(sw, _id, _reached_root, _nr_of_frames, _frames);
   146   }
   324   _written = true;
   147   JfrStackFrame* frames = tl->stackframes();
   325 }
   148   if (frames == NULL) {
   326 
   149     // pending oom
   327 void JfrStackTraceRepository::StackTrace::write(JfrCheckpointWriter& cpw) const {
   150     return 0;
   328   write_stacktrace(cpw, _id, _reached_root, _nr_of_frames, _frames);
   151   }
   329 }
   152   assert(frames != NULL, "invariant");
   330 
   153   assert(tl->stackframes() == frames, "invariant");
   331 // JfrStackFrame
   154   return instance().record_for((JavaThread*)thread, skip,frames, tl->stackdepth());
   332 
   155 }
   333 bool JfrStackFrame::equals(const JfrStackFrame& rhs) const {
   156 
   334   return _methodid == rhs._methodid && _bci == rhs._bci && _type == rhs._type;
   157 traceid JfrStackTraceRepository::record_for(JavaThread* thread, int skip, JfrStackFrame *frames, u4 max_frames) {
   335 }
   158   JfrStackTrace stacktrace(frames, max_frames);
   336 
   159   return stacktrace.record_safe(thread, skip) ? add(stacktrace) : 0;
   337 template <typename Writer>
   160 }
   338 static void write_frame(Writer& w, traceid methodid, int line, int bci, u1 type) {
   161 
   339   w.write((u8)methodid);
   162 traceid JfrStackTraceRepository::add(const JfrStackTrace* stacktrace, JavaThread* thread) {
   340   w.write((u4)line);
   163   assert(stacktrace != NULL, "invariant");
   341   w.write((u4)bci);
   164   assert(thread != NULL, "invariant");
   342   w.write((u8)type);
   165   assert(stacktrace->hash() != 0, "invariant");
   343 }
   166   return add(*stacktrace);
   344 
   167 }
   345 void JfrStackFrame::write(JfrChunkWriter& cw) const {
   168 
   346   write_frame(cw, _methodid, _line, _bci, _type);
   169 traceid JfrStackTraceRepository::add(const JfrStackTrace& stacktrace) {
   347 }
   170   traceid tid = instance().add_trace(stacktrace);
   348 
   171   if (tid == 0) {
   349 void JfrStackFrame::write(JfrCheckpointWriter& cpw) const {
   172     stacktrace.resolve_linenos();
   350   write_frame(cpw, _methodid, _line, _bci, _type);
   173     tid = instance().add_trace(stacktrace);
       
   174   }
       
   175   assert(tid != 0, "invariant");
       
   176   return tid;
       
   177 }
       
   178 
       
   179 traceid JfrStackTraceRepository::add_trace(const JfrStackTrace& stacktrace) {
       
   180   MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
       
   181   const size_t index = stacktrace._hash % TABLE_SIZE;
       
   182   const JfrStackTrace* table_entry = _table[index];
       
   183 
       
   184   while (table_entry != NULL) {
       
   185     if (table_entry->equals(stacktrace)) {
       
   186       return table_entry->id();
       
   187     }
       
   188     table_entry = table_entry->next();
       
   189   }
       
   190 
       
   191   if (!stacktrace.have_lineno()) {
       
   192     return 0;
       
   193   }
       
   194 
       
   195   traceid id = ++_next_id;
       
   196   _table[index] = new JfrStackTrace(id, stacktrace, _table[index]);
       
   197   ++_entries;
       
   198   return id;
   351 }
   199 }
   352 
   200 
   353 // invariant is that the entry to be resolved actually exists in the table
   201 // 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 {
   202 const JfrStackTrace* JfrStackTraceRepository::lookup(unsigned int hash, traceid id) const {
   355   const size_t index = (hash % TABLE_SIZE);
   203   const size_t index = (hash % TABLE_SIZE);
   356   const StackTrace* trace = _table[index];
   204   const JfrStackTrace* trace = _table[index];
   357   while (trace != NULL && trace->id() != id) {
   205   while (trace != NULL && trace->id() != id) {
   358     trace = trace->next();
   206     trace = trace->next();
   359   }
   207   }
   360   assert(trace != NULL, "invariant");
   208   assert(trace != NULL, "invariant");
   361   assert(trace->hash() == hash, "invariant");
   209   assert(trace->hash() == hash, "invariant");
   362   assert(trace->id() == id, "invariant");
   210   assert(trace->id() == id, "invariant");
   363   return trace;
   211   return trace;
   364 }
   212 }
   365 
   213 
   366 void JfrStackFrame::resolve_lineno() {
   214 bool JfrStackTraceRepository::fill_stacktrace_for(JavaThread* thread, JfrStackTrace* stacktrace, int skip) {
   367   assert(_method, "no method pointer");
   215   assert(thread == Thread::current(), "invariant");
   368   assert(_line == 0, "already have linenumber");
   216   assert(stacktrace != NULL, "invariant");
   369   _line = _method->line_number_from_bci(_bci);
   217   JfrThreadLocal* const tl = thread->jfr_thread_local();
   370 }
   218   assert(tl != NULL, "invariant");
   371 
   219   const unsigned int cached_stacktrace_hash = tl->cached_stack_trace_hash();
   372 void JfrStackTrace::set_frame(u4 frame_pos, JfrStackFrame& frame) {
   220   if (cached_stacktrace_hash != 0) {
   373   assert(frame_pos < _max_frames, "illegal frame_pos");
   221     stacktrace->set_hash(cached_stacktrace_hash);
   374   _frames[frame_pos] = frame;
   222     return true;
   375 }
   223   }
   376 
   224   return stacktrace->record_safe(thread, skip);
   377 void JfrStackTrace::resolve_linenos() {
   225 }
   378   for(unsigned int i = 0; i < _nr_of_frames; i++) {
   226 
   379     _frames[i].resolve_lineno();
       
   380   }
       
   381   _lineno = true;
       
   382 }
       
   383 
       
   384 bool JfrStackTrace::record_safe(JavaThread* thread, int skip, bool leakp /* false */) {
       
   385   assert(thread == Thread::current(), "Thread stack needs to be walkable");
       
   386   vframeStream vfs(thread);
       
   387   u4 count = 0;
       
   388   _reached_root = true;
       
   389   for(int i = 0; i < skip; i++) {
       
   390     if (vfs.at_end()) {
       
   391       break;
       
   392     }
       
   393     vfs.next();
       
   394   }
       
   395 
       
   396   while (!vfs.at_end()) {
       
   397     if (count >= _max_frames) {
       
   398       _reached_root = false;
       
   399       break;
       
   400     }
       
   401     const Method* method = vfs.method();
       
   402     const traceid mid = JfrTraceId::use(method, leakp);
       
   403     int type = vfs.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
       
   404     int bci = 0;
       
   405     if (method->is_native()) {
       
   406       type = JfrStackFrame::FRAME_NATIVE;
       
   407     } else {
       
   408       bci = vfs.bci();
       
   409     }
       
   410     // Can we determine if it's inlined?
       
   411     _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
       
   412     _frames[count] = JfrStackFrame(mid, bci, type, method);
       
   413     vfs.next();
       
   414     count++;
       
   415   }
       
   416 
       
   417   _nr_of_frames = count;
       
   418   return true;
       
   419 }
       
   420 
       
   421 bool JfrStackTrace::record_thread(JavaThread& thread, frame& frame) {
       
   422   vframeStreamSamples st(&thread, frame, false);
       
   423   u4 count = 0;
       
   424   _reached_root = true;
       
   425 
       
   426   while (!st.at_end()) {
       
   427     if (count >= _max_frames) {
       
   428       _reached_root = false;
       
   429       break;
       
   430     }
       
   431     const Method* method = st.method();
       
   432     if (!Method::is_valid_method(method)) {
       
   433       // we throw away everything we've gathered in this sample since
       
   434       // none of it is safe
       
   435       return false;
       
   436     }
       
   437     const traceid mid = JfrTraceId::use(method);
       
   438     int type = st.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
       
   439     int bci = 0;
       
   440     if (method->is_native()) {
       
   441       type = JfrStackFrame::FRAME_NATIVE;
       
   442     } else {
       
   443       bci = st.bci();
       
   444     }
       
   445     const int lineno = method->line_number_from_bci(bci);
       
   446     // Can we determine if it's inlined?
       
   447     _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
       
   448     _frames[count] = JfrStackFrame(method, mid, bci, type, lineno);
       
   449     st.samples_next();
       
   450     count++;
       
   451   }
       
   452 
       
   453   _lineno = true;
       
   454   _nr_of_frames = count;
       
   455   return true;
       
   456 }
       
   457 
       
   458 void JfrStackTraceRepository::write_metadata(JfrCheckpointWriter& writer) {
       
   459   JfrFrameType fct;
       
   460   writer.write_type(TYPE_FRAMETYPE);
       
   461   fct.serialize(writer);
       
   462 }