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