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/metadata/jfrSerializer.hpp"
27 #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
28 #include "jfr/recorder/repository/jfrChunkWriter.hpp"
29 #include "jfr/recorder/service/jfrOptionSet.hpp"
30 #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
31 #include "jfr/utilities/jfrTypes.hpp"
32 #include "memory/allocation.inline.hpp"
33 #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 int loop_count = 0;
73 int loop_max = JfrOptionSet::stackdepth() * 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
85 static JfrStackTraceRepository* _instance = NULL;
86
87 JfrStackTraceRepository& JfrStackTraceRepository::instance() {
88 return *_instance;
89 }
90
91 JfrStackTraceRepository* JfrStackTraceRepository::create() {
92 assert(_instance == NULL, "invariant");
93 _instance = new JfrStackTraceRepository();
94 return _instance;
95 }
96
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 {
107 public:
108 void serialize(JfrCheckpointWriter& writer) {
109 writer.write_count(JfrStackFrame::NUM_FRAME_TYPES);
110 writer.write_key(JfrStackFrame::FRAME_INTERPRETER);
111 writer.write("Interpreted");
112 writer.write_key(JfrStackFrame::FRAME_JIT);
113 writer.write("JIT compiled");
114 writer.write_key(JfrStackFrame::FRAME_INLINE);
115 writer.write("Inlined");
116 writer.write_key(JfrStackFrame::FRAME_NATIVE);
117 writer.write("Native");
118 }
119 };
120
121 bool JfrStackTraceRepository::initialize() {
122 return JfrSerializer::register_serializer(TYPE_FRAMETYPE, false, true, new JfrFrameType());
123 }
124
125 size_t JfrStackTraceRepository::clear() {
126 MutexLockerEx lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
127 if (_entries == 0) {
128 return 0;
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 MutexLockerEx 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 return instance().add_trace(stacktrace);
168 }
169
170 traceid JfrStackTraceRepository::record(Thread* thread, int skip /* 0 */) {
171 assert(thread == Thread::current(), "invariant");
172 JfrThreadLocal* const tl = thread->jfr_thread_local();
173 assert(tl != NULL, "invariant");
174 if (tl->has_cached_stack_trace()) {
175 return tl->cached_stack_trace_id();
176 }
177 if (!thread->is_Java_thread() || thread->is_hidden_from_external_view()) {
178 return 0;
179 }
180 JfrStackFrame* frames = tl->stackframes();
181 if (frames == NULL) {
182 // pending oom
183 return 0;
184 }
185 assert(frames != NULL, "invariant");
186 assert(tl->stackframes() == frames, "invariant");
187 return instance().record_for((JavaThread*)thread, skip,frames, tl->stackdepth());
188 }
189
190 traceid JfrStackTraceRepository::record(Thread* thread, int skip, unsigned int* hash) {
191 assert(thread == Thread::current(), "invariant");
192 JfrThreadLocal* const tl = thread->jfr_thread_local();
193 assert(tl != NULL, "invariant");
194
195 if (tl->has_cached_stack_trace()) {
196 *hash = tl->cached_stack_trace_hash();
197 return tl->cached_stack_trace_id();
198 }
199 if (!thread->is_Java_thread() || thread->is_hidden_from_external_view()) {
200 return 0;
201 }
202 JfrStackFrame* frames = tl->stackframes();
203 if (frames == NULL) {
204 // pending oom
205 return 0;
206 }
207 assert(frames != NULL, "invariant");
208 assert(tl->stackframes() == frames, "invariant");
209 return instance().record_for((JavaThread*)thread, skip, frames, tl->stackdepth(), hash);
210 }
211
212 traceid JfrStackTraceRepository::record_for(JavaThread* thread, int skip, JfrStackFrame *frames, u4 max_frames) {
213 JfrStackTrace stacktrace(frames, max_frames);
214 if (!stacktrace.record_safe(thread, skip)) {
215 return 0;
216 }
217 traceid tid = add(stacktrace);
218 if (tid == 0) {
219 stacktrace.resolve_linenos();
220 tid = add(stacktrace);
221 }
222 return tid;
223 }
224
225 traceid JfrStackTraceRepository::record_for(JavaThread* thread, int skip, JfrStackFrame *frames, u4 max_frames, unsigned int* hash) {
226 assert(hash != NULL && *hash == 0, "invariant");
227 JfrStackTrace stacktrace(frames, max_frames);
228 if (!stacktrace.record_safe(thread, skip, true)) {
229 return 0;
230 }
231 traceid tid = add(stacktrace);
232 if (tid == 0) {
233 stacktrace.resolve_linenos();
234 tid = add(stacktrace);
235 }
236 *hash = stacktrace._hash;
237 return tid;
238 }
239
240 size_t JfrStackTraceRepository::write_impl(JfrChunkWriter& sw, bool clear) {
241 MutexLockerEx lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
242 assert(_entries > 0, "invariant");
243 int count = 0;
244 for (u4 i = 0; i < TABLE_SIZE; ++i) {
245 JfrStackTraceRepository::StackTrace* stacktrace = _table[i];
246 while (stacktrace != NULL) {
247 JfrStackTraceRepository::StackTrace* next = stacktrace->next();
248 if (stacktrace->should_write()) {
249 stacktrace->write(sw);
250 ++count;
251 }
252 if (clear) {
253 delete stacktrace;
254 }
255 stacktrace = next;
256 }
257 }
258 if (clear) {
259 memset(_table, 0, sizeof(_table));
260 _entries = 0;
261 }
262 return count;
263 }
264
265 size_t JfrStackTraceRepository::write(JfrChunkWriter& sw, bool clear) {
266 return _entries > 0 ? write_impl(sw, clear) : 0;
267 }
268
269 traceid JfrStackTraceRepository::write(JfrCheckpointWriter& writer, traceid id, unsigned int hash) {
270 assert(JfrStacktrace_lock->owned_by_self(), "invariant");
271 const StackTrace* const trace = resolve_entry(hash, id);
272 assert(trace != NULL, "invariant");
273 assert(trace->hash() == hash, "invariant");
274 assert(trace->id() == id, "invariant");
275 trace->write(writer);
276 return id;
277 }
278
279 JfrStackTraceRepository::StackTrace::StackTrace(traceid id, const JfrStackTrace& trace, JfrStackTraceRepository::StackTrace* next) :
280 _next(next),
281 _frames(NULL),
282 _id(id),
283 _nr_of_frames(trace._nr_of_frames),
284 _hash(trace._hash),
285 _reached_root(trace._reached_root),
286 _written(false) {
287 if (_nr_of_frames > 0) {
288 _frames = NEW_C_HEAP_ARRAY(JfrStackFrame, _nr_of_frames, mtTracing);
289 memcpy(_frames, trace._frames, _nr_of_frames * sizeof(JfrStackFrame));
290 }
291 }
292
293 JfrStackTraceRepository::StackTrace::~StackTrace() {
294 if (_frames != NULL) {
295 FREE_C_HEAP_ARRAY(JfrStackFrame, _frames);
296 }
297 }
298
299 bool JfrStackTraceRepository::StackTrace::equals(const JfrStackTrace& rhs) const {
300 if (_reached_root != rhs._reached_root || _nr_of_frames != rhs._nr_of_frames || _hash != rhs._hash) {
301 return false;
302 }
303 for (u4 i = 0; i < _nr_of_frames; ++i) {
304 if (!_frames[i].equals(rhs._frames[i])) {
305 return false;
306 }
307 }
308 return true;
309 }
310
311 template <typename Writer>
312 static void write_stacktrace(Writer& w, traceid id, bool reached_root, u4 nr_of_frames, const JfrStackFrame* frames) {
313 w.write((u8)id);
314 w.write((u1)!reached_root);
315 w.write(nr_of_frames);
316 for (u4 i = 0; i < nr_of_frames; ++i) {
317 frames[i].write(w);
318 }
319 }
320
321 void JfrStackTraceRepository::StackTrace::write(JfrChunkWriter& sw) const {
322 assert(!_written, "invariant");
323 write_stacktrace(sw, _id, _reached_root, _nr_of_frames, _frames);
324 _written = true;
325 }
326
327 void JfrStackTraceRepository::StackTrace::write(JfrCheckpointWriter& cpw) const {
328 write_stacktrace(cpw, _id, _reached_root, _nr_of_frames, _frames);
329 }
330
331 // JfrStackFrame
332
333 bool JfrStackFrame::equals(const JfrStackFrame& rhs) const {
334 return _methodid == rhs._methodid && _bci == rhs._bci && _type == rhs._type;
335 }
336
337 template <typename Writer>
338 static void write_frame(Writer& w, traceid methodid, int line, int bci, u1 type) {
339 w.write((u8)methodid);
340 w.write((u4)line);
341 w.write((u4)bci);
342 w.write((u8)type);
343 }
344
345 void JfrStackFrame::write(JfrChunkWriter& cw) const {
346 write_frame(cw, _methodid, _line, _bci, _type);
347 }
348
349 void JfrStackFrame::write(JfrCheckpointWriter& cpw) const {
350 write_frame(cpw, _methodid, _line, _bci, _type);
351 }
352
353 // invariant is that the entry to be resolved actually exists in the table
354 const JfrStackTraceRepository::StackTrace* JfrStackTraceRepository::resolve_entry(unsigned int hash, traceid id) const {
355 const size_t index = (hash % TABLE_SIZE);
356 const StackTrace* trace = _table[index];
357 while (trace != NULL && trace->id() != id) {
358 trace = trace->next();
359 }
360 assert(trace != NULL, "invariant");
361 assert(trace->hash() == hash, "invariant");
362 assert(trace->id() == id, "invariant");
363 return trace;
364 }
365
366 void JfrStackFrame::resolve_lineno() {
367 assert(_method, "no method pointer");
368 assert(_line == 0, "already have linenumber");
369 _line = _method->line_number_from_bci(_bci);
370 _method = NULL;
371 }
372
373 void JfrStackTrace::set_frame(u4 frame_pos, JfrStackFrame& frame) {
374 assert(frame_pos < _max_frames, "illegal frame_pos");
375 _frames[frame_pos] = frame;
376 }
377
378 void JfrStackTrace::resolve_linenos() {
379 for(unsigned int i = 0; i < _nr_of_frames; i++) {
380 _frames[i].resolve_lineno();
381 }
382 _lineno = true;
383 }
384
385 bool JfrStackTrace::record_safe(JavaThread* thread, int skip, bool leakp /* false */) {
386 assert(thread == Thread::current(), "Thread stack needs to be walkable");
387 vframeStream vfs(thread);
388 u4 count = 0;
389 _reached_root = true;
390 for(int i = 0; i < skip; i++) {
391 if (vfs.at_end()) {
392 break;
393 }
394 vfs.next();
395 }
396
397 while (!vfs.at_end()) {
398 if (count >= _max_frames) {
399 _reached_root = false;
400 break;
401 }
402 const Method* method = vfs.method();
403 const traceid mid = JfrTraceId::use(method, leakp);
404 int type = vfs.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
405 int bci = 0;
406 if (method->is_native()) {
407 type = JfrStackFrame::FRAME_NATIVE;
408 } else {
409 bci = vfs.bci();
410 }
411 // Can we determine if it's inlined?
412 _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
413 _frames[count] = JfrStackFrame(mid, bci, type, method);
414 vfs.next();
415 count++;
416 }
417
418 _nr_of_frames = count;
419 return true;
420 }
421
422 bool JfrStackTrace::record_thread(JavaThread& thread, frame& frame) {
423 vframeStreamSamples st(&thread, frame, false);
424 u4 count = 0;
425 _reached_root = true;
426
427 while (!st.at_end()) {
428 if (count >= _max_frames) {
429 _reached_root = false;
430 break;
431 }
432 const Method* method = st.method();
433 if (!Method::is_valid_method(method)) {
434 // we throw away everything we've gathered in this sample since
435 // none of it is safe
436 return false;
437 }
438 const traceid mid = JfrTraceId::use(method);
439 int type = st.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
440 int bci = 0;
441 if (method->is_native()) {
442 type = JfrStackFrame::FRAME_NATIVE;
443 } else {
444 bci = st.bci();
445 }
446 const int lineno = method->line_number_from_bci(bci);
447 // Can we determine if it's inlined?
448 _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
449 _frames[count] = JfrStackFrame(mid, bci, type, lineno);
450 st.samples_next();
451 count++;
452 }
453
454 _lineno = true;
455 _nr_of_frames = count;
456 return true;
457 }
458
459 void JfrStackTraceRepository::write_metadata(JfrCheckpointWriter& writer) {
460 JfrFrameType fct;
461 writer.write_type(TYPE_FRAMETYPE);
462 fct.serialize(writer);
463 }
--- EOF ---