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