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   FREE_C_HEAP_ARRAY(JfrStackFrame, _frames);
276 }
277 
278 bool JfrStackTraceRepository::StackTrace::equals(const JfrStackTrace& rhs) const {
279   if (_reached_root != rhs._reached_root || _nr_of_frames != rhs._nr_of_frames || _hash != rhs._hash) {
280     return false;
281   }
282   for (u4 i = 0; i < _nr_of_frames; ++i) {
283     if (!_frames[i].equals(rhs._frames[i])) {
284       return false;
285     }
286   }
287   return true;
288 }
289 
290 template <typename Writer>
291 static void write_stacktrace(Writer& w, traceid id, bool reached_root, u4 nr_of_frames, const JfrStackFrame* frames) {
292   w.write((u8)id);
293   w.write((u1)!reached_root);
294   w.write(nr_of_frames);
295   for (u4 i = 0; i < nr_of_frames; ++i) {
296     frames[i].write(w);
297   }
298 }
299 
300 void JfrStackTraceRepository::StackTrace::write(JfrChunkWriter& sw) const {
301   assert(!_written, "invariant");
302   write_stacktrace(sw, _id, _reached_root, _nr_of_frames, _frames);
303   _written = true;
304 }
305 
306 void JfrStackTraceRepository::StackTrace::write(JfrCheckpointWriter& cpw) const {
307   write_stacktrace(cpw, _id, _reached_root, _nr_of_frames, _frames);
308 }
309 
310 // JfrStackFrame
311 
312 bool JfrStackFrame::equals(const JfrStackFrame& rhs) const {
313   return _methodid == rhs._methodid && _bci == rhs._bci && _type == rhs._type;
314 }
315 
316 template <typename Writer>
317 static void write_frame(Writer& w, traceid methodid, int line, int bci, u1 type) {
318   w.write((u8)methodid);
319   w.write((u4)line);
320   w.write((u4)bci);
321   w.write((u8)type);
322 }
323 
324 void JfrStackFrame::write(JfrChunkWriter& cw) const {
325   write_frame(cw, _methodid, _line, _bci, _type);
326 }
327 
328 void JfrStackFrame::write(JfrCheckpointWriter& cpw) const {
329   write_frame(cpw, _methodid, _line, _bci, _type);
330 }
331 
332 // invariant is that the entry to be resolved actually exists in the table
333 const JfrStackTraceRepository::StackTrace* JfrStackTraceRepository::resolve_entry(unsigned int hash, traceid id) const {
334   const size_t index = (hash % TABLE_SIZE);
335   const StackTrace* trace = _table[index];
336   while (trace != NULL && trace->id() != id) {
337     trace = trace->next();
338   }
339   assert(trace != NULL, "invariant");
340   assert(trace->hash() == hash, "invariant");
341   assert(trace->id() == id, "invariant");
342   return trace;
343 }
344 
345 void JfrStackFrame::resolve_lineno() const {
346   assert(_method, "no method pointer");
347   assert(_line == 0, "already have linenumber");
348   _line = _method->line_number_from_bci(_bci);
349   _method = NULL;
350 }
351 
352 void JfrStackTrace::set_frame(u4 frame_pos, JfrStackFrame& frame) {
353   assert(frame_pos < _max_frames, "illegal frame_pos");
354   _frames[frame_pos] = frame;
355 }
356 
357 void JfrStackTrace::resolve_linenos() const {
358   for(unsigned int i = 0; i < _nr_of_frames; i++) {
359     _frames[i].resolve_lineno();
360   }
361   _lineno = true;
362 }
363 
364 bool JfrStackTrace::record_safe(JavaThread* thread, int skip, bool leakp /* false */) {
365   assert(thread == Thread::current(), "Thread stack needs to be walkable");
366   vframeStream vfs(thread);
367   u4 count = 0;
368   _reached_root = true;
369   for(int i = 0; i < skip; i++) {
370     if (vfs.at_end()) {
371       break;
372     }
373     vfs.next();
374   }
375 
376   while (!vfs.at_end()) {
377     if (count >= _max_frames) {
378       _reached_root = false;
379       break;
380     }
381     const Method* method = vfs.method();
382     const traceid mid = JfrTraceId::use(method, leakp);
383     int type = vfs.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
384     int bci = 0;
385     if (method->is_native()) {
386       type = JfrStackFrame::FRAME_NATIVE;
387     } else {
388       bci = vfs.bci();
389     }
390     // Can we determine if it's inlined?
391     _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
392     _frames[count] = JfrStackFrame(mid, bci, type, method);
393     vfs.next();
394     count++;
395   }
396 
397   _nr_of_frames = count;
398   return true;
399 }
400 
401 bool JfrStackTrace::record_thread(JavaThread& thread, frame& frame) {
402   vframeStreamSamples st(&thread, frame, false);
403   u4 count = 0;
404   _reached_root = true;
405 
406   while (!st.at_end()) {
407     if (count >= _max_frames) {
408       _reached_root = false;
409       break;
410     }
411     const Method* method = st.method();
412     if (!Method::is_valid_method(method)) {
413       // we throw away everything we've gathered in this sample since
414       // none of it is safe
415       return false;
416     }
417     const traceid mid = JfrTraceId::use(method);
418     int type = st.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
419     int bci = 0;
420     if (method->is_native()) {
421       type = JfrStackFrame::FRAME_NATIVE;
422     } else {
423       bci = st.bci();
424     }
425     const int lineno = method->line_number_from_bci(bci);
426     // Can we determine if it's inlined?
427     _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
428     _frames[count] = JfrStackFrame(mid, bci, type, lineno);
429     st.samples_next();
430     count++;
431   }
432 
433   _lineno = true;
434   _nr_of_frames = count;
435   return true;
436 }
437 
438 void JfrStackTraceRepository::write_metadata(JfrCheckpointWriter& writer) {
439   JfrFrameType fct;
440   writer.write_type(TYPE_FRAMETYPE);
441   fct.serialize(writer);
442 }