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