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