src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp
changeset 58132 caa25ab47aca
parent 58084 cddef3bde924
child 58157 9dca61a7df19
child 58679 9c3209ff7550
child 58863 c16ac7a2eba4
--- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp	Fri Sep 13 16:03:31 2019 -0700
+++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp	Sat Sep 14 14:40:09 2019 +0200
@@ -24,66 +24,18 @@
 
 #include "precompiled.hpp"
 #include "jfr/metadata/jfrSerializer.hpp"
-#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
 #include "jfr/recorder/repository/jfrChunkWriter.hpp"
-#include "jfr/recorder/service/jfrOptionSet.hpp"
 #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
-#include "jfr/utilities/jfrTypes.hpp"
-#include "memory/allocation.inline.hpp"
+#include "jfr/support/jfrThreadLocal.hpp"
 #include "runtime/mutexLocker.hpp"
-#include "runtime/os.inline.hpp"
-#include "runtime/safepoint.hpp"
-#include "runtime/task.hpp"
-#include "runtime/vframe.inline.hpp"
-
-class vframeStreamSamples : public vframeStreamCommon {
- public:
-  // constructor that starts with sender of frame fr (top_frame)
-  vframeStreamSamples(JavaThread *jt, frame fr, bool stop_at_java_call_stub);
-  void samples_next();
-  void stop() {}
-};
-
-vframeStreamSamples::vframeStreamSamples(JavaThread *jt, frame fr, bool stop_at_java_call_stub) : vframeStreamCommon(jt) {
-  _stop_at_java_call_stub = stop_at_java_call_stub;
-  _frame = fr;
-
-  // We must always have a valid frame to start filling
-  bool filled_in = fill_from_frame();
-  assert(filled_in, "invariant");
-}
-
-// Solaris SPARC Compiler1 needs an additional check on the grandparent
-// of the top_frame when the parent of the top_frame is interpreted and
-// the grandparent is compiled. However, in this method we do not know
-// the relationship of the current _frame relative to the top_frame so
-// we implement a more broad sanity check. When the previous callee is
-// interpreted and the current sender is compiled, we verify that the
-// current sender is also walkable. If it is not walkable, then we mark
-// the current vframeStream as at the end.
-void vframeStreamSamples::samples_next() {
-  // handle frames with inlining
-  if (_mode == compiled_mode &&
-      vframeStreamCommon::fill_in_compiled_inlined_sender()) {
-    return;
-  }
-
-  // handle general case
-  u4 loop_count = 0;
-  u4 loop_max = MAX_STACK_DEPTH * 2;
-  do {
-    loop_count++;
-    // By the time we get here we should never see unsafe but better safe then segv'd
-    if (loop_count > loop_max || !_frame.safe_for_sender(_thread)) {
-      _mode = at_end_mode;
-      return;
-    }
-    _frame = _frame.sender(&_reg_map);
-  } while (!fill_from_frame());
-}
 
 static JfrStackTraceRepository* _instance = NULL;
 
+JfrStackTraceRepository::JfrStackTraceRepository() : _next_id(0), _entries(0) {
+  memset(_table, 0, sizeof(_table));
+}
+
 JfrStackTraceRepository& JfrStackTraceRepository::instance() {
   return *_instance;
 }
@@ -94,15 +46,6 @@
   return _instance;
 }
 
-void JfrStackTraceRepository::destroy() {
-  assert(_instance != NULL, "invarinat");
-  delete _instance;
-  _instance = NULL;
-}
-
-JfrStackTraceRepository::JfrStackTraceRepository() : _next_id(0), _entries(0) {
-  memset(_table, 0, sizeof(_table));
-}
 class JfrFrameType : public JfrSerializer {
  public:
   void serialize(JfrCheckpointWriter& writer) {
@@ -122,100 +65,10 @@
   return JfrSerializer::register_serializer(TYPE_FRAMETYPE, false, true, new JfrFrameType());
 }
 
-size_t JfrStackTraceRepository::clear() {
-  MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
-  if (_entries == 0) {
-    return 0;
-  }
-  for (u4 i = 0; i < TABLE_SIZE; ++i) {
-    JfrStackTraceRepository::StackTrace* stacktrace = _table[i];
-    while (stacktrace != NULL) {
-      JfrStackTraceRepository::StackTrace* next = stacktrace->next();
-      delete stacktrace;
-      stacktrace = next;
-    }
-  }
-  memset(_table, 0, sizeof(_table));
-  const size_t processed = _entries;
-  _entries = 0;
-  return processed;
-}
-
-traceid JfrStackTraceRepository::add_trace(const JfrStackTrace& stacktrace) {
-  MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
-  const size_t index = stacktrace._hash % TABLE_SIZE;
-  const StackTrace* table_entry = _table[index];
-
-  while (table_entry != NULL) {
-    if (table_entry->equals(stacktrace)) {
-      return table_entry->id();
-    }
-    table_entry = table_entry->next();
-  }
-
-  if (!stacktrace.have_lineno()) {
-    return 0;
-  }
-
-  traceid id = ++_next_id;
-  _table[index] = new StackTrace(id, stacktrace, _table[index]);
-  ++_entries;
-  return id;
-}
-
-traceid JfrStackTraceRepository::add(const JfrStackTrace& stacktrace) {
-  traceid tid = instance().add_trace(stacktrace);
-  if (tid == 0) {
-    stacktrace.resolve_linenos();
-    tid = instance().add_trace(stacktrace);
-  }
-  assert(tid != 0, "invariant");
-  return tid;
-}
-
-traceid JfrStackTraceRepository::record(Thread* thread, int skip /* 0 */) {
-  assert(thread == Thread::current(), "invariant");
-  JfrThreadLocal* const tl = thread->jfr_thread_local();
-  assert(tl != NULL, "invariant");
-  if (tl->has_cached_stack_trace()) {
-    return tl->cached_stack_trace_id();
-  }
-  if (!thread->is_Java_thread() || thread->is_hidden_from_external_view()) {
-    return 0;
-  }
-  JfrStackFrame* frames = tl->stackframes();
-  if (frames == NULL) {
-    // pending oom
-    return 0;
-  }
-  assert(frames != NULL, "invariant");
-  assert(tl->stackframes() == frames, "invariant");
-  return instance().record_for((JavaThread*)thread, skip,frames, tl->stackdepth());
-}
-
-traceid JfrStackTraceRepository::record_for(JavaThread* thread, int skip, JfrStackFrame *frames, u4 max_frames) {
-  JfrStackTrace stacktrace(frames, max_frames);
-  return stacktrace.record_safe(thread, skip) ? add(stacktrace) : 0;
-}
-
-traceid JfrStackTraceRepository::add(const JfrStackTrace* stacktrace, JavaThread* thread) {
-  assert(stacktrace != NULL, "invariant");
-  assert(thread != NULL, "invariant");
-  assert(stacktrace->hash() != 0, "invariant");
-  return add(*stacktrace);
-}
-
-bool JfrStackTraceRepository::fill_stacktrace_for(JavaThread* thread, JfrStackTrace* stacktrace, int skip) {
-  assert(thread == Thread::current(), "invariant");
-  assert(stacktrace != NULL, "invariant");
-  JfrThreadLocal* const tl = thread->jfr_thread_local();
-  assert(tl != NULL, "invariant");
-  const unsigned int cached_stacktrace_hash = tl->cached_stack_trace_hash();
-  if (cached_stacktrace_hash != 0) {
-    stacktrace->set_hash(cached_stacktrace_hash);
-    return true;
-  }
-  return stacktrace->record_safe(thread, skip, true);
+void JfrStackTraceRepository::destroy() {
+  assert(_instance != NULL, "invarinat");
+  delete _instance;
+  _instance = NULL;
 }
 
 size_t JfrStackTraceRepository::write_impl(JfrChunkWriter& sw, bool clear) {
@@ -223,9 +76,9 @@
   assert(_entries > 0, "invariant");
   int count = 0;
   for (u4 i = 0; i < TABLE_SIZE; ++i) {
-    JfrStackTraceRepository::StackTrace* stacktrace = _table[i];
+    JfrStackTrace* stacktrace = _table[i];
     while (stacktrace != NULL) {
-      JfrStackTraceRepository::StackTrace* next = stacktrace->next();
+      JfrStackTrace* next = const_cast<JfrStackTrace*>(stacktrace->next());
       if (stacktrace->should_write()) {
         stacktrace->write(sw);
         ++count;
@@ -249,7 +102,7 @@
 
 traceid JfrStackTraceRepository::write(JfrCheckpointWriter& writer, traceid id, unsigned int hash) {
   assert(JfrStacktrace_lock->owned_by_self(), "invariant");
-  const StackTrace* const trace = resolve_entry(hash, id);
+  const JfrStackTrace* const trace = lookup(hash, id);
   assert(trace != NULL, "invariant");
   assert(trace->hash() == hash, "invariant");
   assert(trace->id() == id, "invariant");
@@ -257,82 +110,105 @@
   return id;
 }
 
-JfrStackTraceRepository::StackTrace::StackTrace(traceid id, const JfrStackTrace& trace, JfrStackTraceRepository::StackTrace* next) :
-  _next(next),
-  _frames(NULL),
-  _id(id),
-  _nr_of_frames(trace._nr_of_frames),
-  _hash(trace._hash),
-  _reached_root(trace._reached_root),
-  _written(false) {
-  if (_nr_of_frames > 0) {
-    _frames = NEW_C_HEAP_ARRAY(JfrStackFrame, _nr_of_frames, mtTracing);
-    memcpy(_frames, trace._frames, _nr_of_frames * sizeof(JfrStackFrame));
+void JfrStackTraceRepository::write_metadata(JfrCheckpointWriter& writer) {
+  JfrFrameType fct;
+  writer.write_type(TYPE_FRAMETYPE);
+  fct.serialize(writer);
+}
+
+size_t JfrStackTraceRepository::clear() {
+  MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
+  if (_entries == 0) {
+    return 0;
+  }
+  for (u4 i = 0; i < TABLE_SIZE; ++i) {
+    JfrStackTrace* stacktrace = _table[i];
+    while (stacktrace != NULL) {
+      JfrStackTrace* next = const_cast<JfrStackTrace*>(stacktrace->next());
+      delete stacktrace;
+      stacktrace = next;
+    }
+  }
+  memset(_table, 0, sizeof(_table));
+  const size_t processed = _entries;
+  _entries = 0;
+  return processed;
+}
+
+traceid JfrStackTraceRepository::record(Thread* thread, int skip /* 0 */) {
+  assert(thread == Thread::current(), "invariant");
+  JfrThreadLocal* const tl = thread->jfr_thread_local();
+  assert(tl != NULL, "invariant");
+  if (tl->has_cached_stack_trace()) {
+    return tl->cached_stack_trace_id();
+  }
+  if (!thread->is_Java_thread() || thread->is_hidden_from_external_view()) {
+    return 0;
+  }
+  JfrStackFrame* frames = tl->stackframes();
+  if (frames == NULL) {
+    // pending oom
+    return 0;
+  }
+  assert(frames != NULL, "invariant");
+  assert(tl->stackframes() == frames, "invariant");
+  return instance().record_for((JavaThread*)thread, skip, frames, tl->stackdepth());
+}
+
+traceid JfrStackTraceRepository::record_for(JavaThread* thread, int skip, JfrStackFrame *frames, u4 max_frames) {
+  JfrStackTrace stacktrace(frames, max_frames);
+  return stacktrace.record_safe(thread, skip) ? add(stacktrace) : 0;
+}
+
+traceid JfrStackTraceRepository::add(const JfrStackTrace& stacktrace) {
+  traceid tid = instance().add_trace(stacktrace);
+  if (tid == 0) {
+    stacktrace.resolve_linenos();
+    tid = instance().add_trace(stacktrace);
+  }
+  assert(tid != 0, "invariant");
+  return tid;
+}
+
+void JfrStackTraceRepository::record_and_cache(JavaThread* thread, int skip /* 0 */) {
+  assert(thread != NULL, "invariant");
+  JfrThreadLocal* const tl = thread->jfr_thread_local();
+  assert(tl != NULL, "invariant");
+  assert(!tl->has_cached_stack_trace(), "invariant");
+  JfrStackTrace stacktrace(tl->stackframes(), tl->stackdepth());
+  stacktrace.record_safe(thread, skip);
+  const unsigned int hash = stacktrace.hash();
+  if (hash != 0) {
+    tl->set_cached_stack_trace_id(instance().add(stacktrace), hash);
   }
 }
 
-JfrStackTraceRepository::StackTrace::~StackTrace() {
-  FREE_C_HEAP_ARRAY(JfrStackFrame, _frames);
-}
-
-bool JfrStackTraceRepository::StackTrace::equals(const JfrStackTrace& rhs) const {
-  if (_reached_root != rhs._reached_root || _nr_of_frames != rhs._nr_of_frames || _hash != rhs._hash) {
-    return false;
-  }
-  for (u4 i = 0; i < _nr_of_frames; ++i) {
-    if (!_frames[i].equals(rhs._frames[i])) {
-      return false;
-    }
-  }
-  return true;
-}
-
-template <typename Writer>
-static void write_stacktrace(Writer& w, traceid id, bool reached_root, u4 nr_of_frames, const JfrStackFrame* frames) {
-  w.write((u8)id);
-  w.write((u1)!reached_root);
-  w.write(nr_of_frames);
-  for (u4 i = 0; i < nr_of_frames; ++i) {
-    frames[i].write(w);
-  }
-}
+traceid JfrStackTraceRepository::add_trace(const JfrStackTrace& stacktrace) {
+  MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
+  const size_t index = stacktrace._hash % TABLE_SIZE;
+  const JfrStackTrace* table_entry = _table[index];
 
-void JfrStackTraceRepository::StackTrace::write(JfrChunkWriter& sw) const {
-  assert(!_written, "invariant");
-  write_stacktrace(sw, _id, _reached_root, _nr_of_frames, _frames);
-  _written = true;
-}
-
-void JfrStackTraceRepository::StackTrace::write(JfrCheckpointWriter& cpw) const {
-  write_stacktrace(cpw, _id, _reached_root, _nr_of_frames, _frames);
-}
-
-// JfrStackFrame
+  while (table_entry != NULL) {
+    if (table_entry->equals(stacktrace)) {
+      return table_entry->id();
+    }
+    table_entry = table_entry->next();
+  }
 
-bool JfrStackFrame::equals(const JfrStackFrame& rhs) const {
-  return _methodid == rhs._methodid && _bci == rhs._bci && _type == rhs._type;
-}
+  if (!stacktrace.have_lineno()) {
+    return 0;
+  }
 
-template <typename Writer>
-static void write_frame(Writer& w, traceid methodid, int line, int bci, u1 type) {
-  w.write((u8)methodid);
-  w.write((u4)line);
-  w.write((u4)bci);
-  w.write((u8)type);
-}
-
-void JfrStackFrame::write(JfrChunkWriter& cw) const {
-  write_frame(cw, _methodid, _line, _bci, _type);
-}
-
-void JfrStackFrame::write(JfrCheckpointWriter& cpw) const {
-  write_frame(cpw, _methodid, _line, _bci, _type);
+  traceid id = ++_next_id;
+  _table[index] = new JfrStackTrace(id, stacktrace, _table[index]);
+  ++_entries;
+  return id;
 }
 
 // invariant is that the entry to be resolved actually exists in the table
-const JfrStackTraceRepository::StackTrace* JfrStackTraceRepository::resolve_entry(unsigned int hash, traceid id) const {
+const JfrStackTrace* JfrStackTraceRepository::lookup(unsigned int hash, traceid id) const {
   const size_t index = (hash % TABLE_SIZE);
-  const StackTrace* trace = _table[index];
+  const JfrStackTrace* trace = _table[index];
   while (trace != NULL && trace->id() != id) {
     trace = trace->next();
   }
@@ -341,102 +217,3 @@
   assert(trace->id() == id, "invariant");
   return trace;
 }
-
-void JfrStackFrame::resolve_lineno() const {
-  assert(_method, "no method pointer");
-  assert(_line == 0, "already have linenumber");
-  _line = _method->line_number_from_bci(_bci);
-  _method = NULL;
-}
-
-void JfrStackTrace::set_frame(u4 frame_pos, JfrStackFrame& frame) {
-  assert(frame_pos < _max_frames, "illegal frame_pos");
-  _frames[frame_pos] = frame;
-}
-
-void JfrStackTrace::resolve_linenos() const {
-  for(unsigned int i = 0; i < _nr_of_frames; i++) {
-    _frames[i].resolve_lineno();
-  }
-  _lineno = true;
-}
-
-bool JfrStackTrace::record_safe(JavaThread* thread, int skip, bool leakp /* false */) {
-  assert(thread == Thread::current(), "Thread stack needs to be walkable");
-  vframeStream vfs(thread);
-  u4 count = 0;
-  _reached_root = true;
-  for(int i = 0; i < skip; i++) {
-    if (vfs.at_end()) {
-      break;
-    }
-    vfs.next();
-  }
-
-  while (!vfs.at_end()) {
-    if (count >= _max_frames) {
-      _reached_root = false;
-      break;
-    }
-    const Method* method = vfs.method();
-    const traceid mid = JfrTraceId::use(method, leakp);
-    int type = vfs.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
-    int bci = 0;
-    if (method->is_native()) {
-      type = JfrStackFrame::FRAME_NATIVE;
-    } else {
-      bci = vfs.bci();
-    }
-    // Can we determine if it's inlined?
-    _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
-    _frames[count] = JfrStackFrame(mid, bci, type, method);
-    vfs.next();
-    count++;
-  }
-
-  _nr_of_frames = count;
-  return true;
-}
-
-bool JfrStackTrace::record_thread(JavaThread& thread, frame& frame) {
-  vframeStreamSamples st(&thread, frame, false);
-  u4 count = 0;
-  _reached_root = true;
-
-  while (!st.at_end()) {
-    if (count >= _max_frames) {
-      _reached_root = false;
-      break;
-    }
-    const Method* method = st.method();
-    if (!Method::is_valid_method(method)) {
-      // we throw away everything we've gathered in this sample since
-      // none of it is safe
-      return false;
-    }
-    const traceid mid = JfrTraceId::use(method);
-    int type = st.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
-    int bci = 0;
-    if (method->is_native()) {
-      type = JfrStackFrame::FRAME_NATIVE;
-    } else {
-      bci = st.bci();
-    }
-    const int lineno = method->line_number_from_bci(bci);
-    // Can we determine if it's inlined?
-    _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
-    _frames[count] = JfrStackFrame(mid, bci, type, lineno);
-    st.samples_next();
-    count++;
-  }
-
-  _lineno = true;
-  _nr_of_frames = count;
-  return true;
-}
-
-void JfrStackTraceRepository::write_metadata(JfrCheckpointWriter& writer) {
-  JfrFrameType fct;
-  writer.write_type(TYPE_FRAMETYPE);
-  fct.serialize(writer);
-}