src/hotspot/share/jfr/recorder/stacktrace/jfrStackTrace.cpp
branchJEP-349-branch
changeset 57870 00860d9caf4d
child 57983 a57907813a83
equal deleted inserted replaced
57862:84ef29ccac56 57870:00860d9caf4d
       
     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/recorder/checkpoint/jfrCheckpointWriter.hpp"
       
    27 #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
       
    28 #include "jfr/recorder/repository/jfrChunkWriter.hpp"
       
    29 #include "jfr/recorder/stacktrace/jfrStackTrace.hpp"
       
    30 #include "memory/allocation.inline.hpp"
       
    31 #include "runtime/vframe.inline.hpp"
       
    32 
       
    33 static void copy_frames(JfrStackFrame** lhs_frames, u4 length, const JfrStackFrame* rhs_frames) {
       
    34   assert(lhs_frames != NULL, "invariant");
       
    35   assert(rhs_frames != NULL, "invariant");
       
    36   if (length > 0) {
       
    37     *lhs_frames = NEW_C_HEAP_ARRAY(JfrStackFrame, length, mtTracing);
       
    38     memcpy(*lhs_frames, rhs_frames, length * sizeof(JfrStackFrame));
       
    39   }
       
    40 }
       
    41 
       
    42 JfrStackFrame::JfrStackFrame(const traceid& id, int bci, int type, InstanceKlass* k) :
       
    43   _klass(k), _methodid(id), _line(0), _bci(bci), _type(type) {}
       
    44 
       
    45 JfrStackFrame::JfrStackFrame(const traceid& id, int bci, int type, int lineno) :
       
    46   _klass(NULL), _methodid(id), _line(lineno), _bci(bci), _type(type) {}
       
    47 
       
    48 JfrStackTrace::JfrStackTrace(JfrStackFrame* frames, u4 max_frames) :
       
    49   _next(NULL),
       
    50   _frames(frames),
       
    51   _id(0),
       
    52   _hash(0),
       
    53   _nr_of_frames(0),
       
    54   _max_frames(max_frames),
       
    55   _frames_ownership(false),
       
    56   _reached_root(false),
       
    57   _lineno(false),
       
    58   _written(false) {}
       
    59 
       
    60 JfrStackTrace::JfrStackTrace(traceid id, const JfrStackTrace& trace, const JfrStackTrace* next) :
       
    61   _next(next),
       
    62   _frames(NULL),
       
    63   _id(id),
       
    64   _hash(trace._hash),
       
    65   _nr_of_frames(trace._nr_of_frames),
       
    66   _max_frames(trace._max_frames),
       
    67   _frames_ownership(true),
       
    68   _reached_root(trace._reached_root),
       
    69   _lineno(trace._lineno),
       
    70   _written(false) {
       
    71   copy_frames(&_frames, trace._nr_of_frames, trace._frames);
       
    72 }
       
    73 
       
    74 JfrStackTrace::~JfrStackTrace() {
       
    75   if (_frames_ownership && _frames != NULL) {
       
    76     FREE_C_HEAP_ARRAY(JfrStackFrame, _frames);
       
    77   }
       
    78 }
       
    79 
       
    80 void JfrStackTrace::operator=(const JfrStackTrace& trace) {
       
    81   assert(_next == NULL, "invariant");
       
    82   assert(_frames_ownership, "invariant");
       
    83 
       
    84   if (_id == trace._id) {
       
    85     assert(_hash == trace._hash, "invariant");
       
    86     assert(_nr_of_frames == trace._nr_of_frames, "invariant");
       
    87     return;
       
    88   }
       
    89   _next = NULL;
       
    90   _id = trace._id;
       
    91   _hash = trace._hash;
       
    92   _nr_of_frames = trace._nr_of_frames;
       
    93   _max_frames = trace._max_frames;
       
    94   _reached_root = trace._reached_root;
       
    95   _lineno = trace._lineno;
       
    96   _written = false;
       
    97   copy_frames(&_frames, trace._nr_of_frames, trace._frames);
       
    98 }
       
    99 
       
   100 template <typename Writer>
       
   101 static void write_stacktrace(Writer& w, traceid id, bool reached_root, u4 nr_of_frames, const JfrStackFrame* frames) {
       
   102   w.write((u8)id);
       
   103   w.write((u1)!reached_root);
       
   104   w.write(nr_of_frames);
       
   105   for (u4 i = 0; i < nr_of_frames; ++i) {
       
   106     frames[i].write(w);
       
   107   }
       
   108 }
       
   109 
       
   110 void JfrStackTrace::write(JfrChunkWriter& sw) const {
       
   111   assert(!_written, "invariant");
       
   112   write_stacktrace(sw, _id, _reached_root, _nr_of_frames, _frames);
       
   113   _written = true;
       
   114 }
       
   115 
       
   116 void JfrStackTrace::write(JfrCheckpointWriter& cpw) const {
       
   117   write_stacktrace(cpw, _id, _reached_root, _nr_of_frames, _frames);
       
   118 }
       
   119 
       
   120 bool JfrStackFrame::equals(const JfrStackFrame& rhs) const {
       
   121   return _methodid == rhs._methodid && _bci == rhs._bci && _type == rhs._type;
       
   122 }
       
   123 
       
   124 bool JfrStackTrace::equals(const JfrStackTrace& rhs) const {
       
   125   if (_reached_root != rhs._reached_root || _nr_of_frames != rhs._nr_of_frames || _hash != rhs._hash) {
       
   126     return false;
       
   127   }
       
   128   for (u4 i = 0; i < _nr_of_frames; ++i) {
       
   129     if (!_frames[i].equals(rhs._frames[i])) {
       
   130       return false;
       
   131     }
       
   132   }
       
   133   return true;
       
   134 }
       
   135 
       
   136 template <typename Writer>
       
   137 static void write_frame(Writer& w, traceid methodid, int line, int bci, u1 type) {
       
   138   w.write((u8)methodid);
       
   139   w.write((u4)line);
       
   140   w.write((u4)bci);
       
   141   w.write((u8)type);
       
   142 }
       
   143 
       
   144 void JfrStackFrame::write(JfrChunkWriter& cw) const {
       
   145   write_frame(cw, _methodid, _line, _bci, _type);
       
   146 }
       
   147 
       
   148 void JfrStackFrame::write(JfrCheckpointWriter& cpw) const {
       
   149   write_frame(cpw, _methodid, _line, _bci, _type);
       
   150 }
       
   151 
       
   152 class vframeStreamSamples : public vframeStreamCommon {
       
   153  public:
       
   154   // constructor that starts with sender of frame fr (top_frame)
       
   155   vframeStreamSamples(JavaThread *jt, frame fr, bool stop_at_java_call_stub) : vframeStreamCommon(jt) {
       
   156     _stop_at_java_call_stub = stop_at_java_call_stub;
       
   157     _frame = fr;
       
   158 
       
   159     // We must always have a valid frame to start filling
       
   160     bool filled_in = fill_from_frame();
       
   161     assert(filled_in, "invariant");
       
   162   }
       
   163   void samples_next();
       
   164   void stop() {}
       
   165 };
       
   166 
       
   167 // Solaris SPARC Compiler1 needs an additional check on the grandparent
       
   168 // of the top_frame when the parent of the top_frame is interpreted and
       
   169 // the grandparent is compiled. However, in this method we do not know
       
   170 // the relationship of the current _frame relative to the top_frame so
       
   171 // we implement a more broad sanity check. When the previous callee is
       
   172 // interpreted and the current sender is compiled, we verify that the
       
   173 // current sender is also walkable. If it is not walkable, then we mark
       
   174 // the current vframeStream as at the end.
       
   175 void vframeStreamSamples::samples_next() {
       
   176   // handle frames with inlining
       
   177   if (_mode == compiled_mode &&
       
   178     vframeStreamCommon::fill_in_compiled_inlined_sender()) {
       
   179     return;
       
   180   }
       
   181 
       
   182   // handle general case
       
   183   u4 loop_count = 0;
       
   184   u4 loop_max = MAX_STACK_DEPTH * 2;
       
   185   do {
       
   186     loop_count++;
       
   187     // By the time we get here we should never see unsafe but better safe then segv'd
       
   188     if (loop_count > loop_max || !_frame.safe_for_sender(_thread)) {
       
   189       _mode = at_end_mode;
       
   190       return;
       
   191     }
       
   192     _frame = _frame.sender(&_reg_map);
       
   193   } while (!fill_from_frame());
       
   194 }
       
   195 
       
   196 bool JfrStackTrace::record_thread(JavaThread& thread, frame& frame) {
       
   197   vframeStreamSamples st(&thread, frame, false);
       
   198   u4 count = 0;
       
   199   _reached_root = true;
       
   200 
       
   201   while (!st.at_end()) {
       
   202     if (count >= _max_frames) {
       
   203       _reached_root = false;
       
   204       break;
       
   205     }
       
   206     const Method* method = st.method();
       
   207     if (!Method::is_valid_method(method)) {
       
   208       // we throw away everything we've gathered in this sample since
       
   209       // none of it is safe
       
   210       return false;
       
   211     }
       
   212     const traceid mid = JfrTraceId::use(method);
       
   213     int type = st.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
       
   214     int bci = 0;
       
   215     if (method->is_native()) {
       
   216       type = JfrStackFrame::FRAME_NATIVE;
       
   217     } else {
       
   218       bci = st.bci();
       
   219     }
       
   220     const int lineno = method->line_number_from_bci(bci);
       
   221     // Can we determine if it's inlined?
       
   222     _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
       
   223     _frames[count] = JfrStackFrame(mid, bci, type, method->constants()->pool_holder());
       
   224     st.samples_next();
       
   225     count++;
       
   226   }
       
   227 
       
   228   _lineno = true;
       
   229   _nr_of_frames = count;
       
   230   return true;
       
   231 }
       
   232 
       
   233 void JfrStackFrame::resolve_lineno() const {
       
   234   assert(_klass, "no klass pointer");
       
   235   assert(_line == 0, "already have linenumber");
       
   236   const int id_num = _methodid & METHOD_ID_NUM_MASK;
       
   237   const Method* const method = _klass->method_with_orig_idnum(id_num);
       
   238   assert(method != NULL, "invariant");
       
   239   _line = method->line_number_from_bci(_bci);
       
   240 }
       
   241 
       
   242 void JfrStackTrace::resolve_linenos() const {
       
   243   for (unsigned int i = 0; i < _nr_of_frames; i++) {
       
   244     _frames[i].resolve_lineno();
       
   245   }
       
   246   _lineno = true;
       
   247 }
       
   248 
       
   249 bool JfrStackTrace::record_safe(JavaThread* thread, int skip) {
       
   250   assert(thread == Thread::current(), "Thread stack needs to be walkable");
       
   251   vframeStream vfs(thread);
       
   252   u4 count = 0;
       
   253   _reached_root = true;
       
   254   for (int i = 0; i < skip; i++) {
       
   255     if (vfs.at_end()) {
       
   256       break;
       
   257     }
       
   258     vfs.next();
       
   259   }
       
   260 
       
   261   while (!vfs.at_end()) {
       
   262     if (count >= _max_frames) {
       
   263       _reached_root = false;
       
   264       break;
       
   265     }
       
   266     const Method* method = vfs.method();
       
   267     const traceid mid = JfrTraceId::use(method);
       
   268     int type = vfs.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
       
   269     int bci = 0;
       
   270     if (method->is_native()) {
       
   271       type = JfrStackFrame::FRAME_NATIVE;
       
   272     }
       
   273     else {
       
   274       bci = vfs.bci();
       
   275     }
       
   276     // Can we determine if it's inlined?
       
   277     _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
       
   278     _frames[count] = JfrStackFrame(mid, bci, type, method->constants()->pool_holder());
       
   279     vfs.next();
       
   280     count++;
       
   281   }
       
   282 
       
   283   _nr_of_frames = count;
       
   284   return true;
       
   285 }
       
   286