1 | /* |
2 | * Copyright (c) 2003, 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 "code/debugInfoRec.hpp" |
27 | #include "code/pcDesc.hpp" |
28 | #include "gc/shared/collectedHeap.inline.hpp" |
29 | #include "memory/universe.hpp" |
30 | #include "oops/oop.inline.hpp" |
31 | #include "prims/forte.hpp" |
32 | #include "runtime/frame.inline.hpp" |
33 | #include "runtime/javaCalls.hpp" |
34 | #include "runtime/thread.inline.hpp" |
35 | #include "runtime/vframe.inline.hpp" |
36 | #include "runtime/vframeArray.hpp" |
37 | |
38 | // call frame copied from old .h file and renamed |
39 | typedef struct { |
40 | jint lineno; // line number in the source file |
41 | jmethodID method_id; // method executed in this frame |
42 | } ASGCT_CallFrame; |
43 | |
44 | // call trace copied from old .h file and renamed |
45 | typedef struct { |
46 | JNIEnv *env_id; // Env where trace was recorded |
47 | jint num_frames; // number of frames in this trace |
48 | ASGCT_CallFrame *frames; // frames |
49 | } ASGCT_CallTrace; |
50 | |
51 | // These name match the names reported by the forte quality kit |
52 | enum { |
53 | ticks_no_Java_frame = 0, |
54 | ticks_no_class_load = -1, |
55 | ticks_GC_active = -2, |
56 | ticks_unknown_not_Java = -3, |
57 | ticks_not_walkable_not_Java = -4, |
58 | ticks_unknown_Java = -5, |
59 | ticks_not_walkable_Java = -6, |
60 | ticks_unknown_state = -7, |
61 | ticks_thread_exit = -8, |
62 | ticks_deopt = -9, |
63 | ticks_safepoint = -10 |
64 | }; |
65 | |
66 | #if INCLUDE_JVMTI |
67 | |
68 | //------------------------------------------------------- |
69 | |
70 | // Native interfaces for use by Forte tools. |
71 | |
72 | |
73 | #if !defined(IA64) |
74 | |
75 | class vframeStreamForte : public vframeStreamCommon { |
76 | public: |
77 | // constructor that starts with sender of frame fr (top_frame) |
78 | vframeStreamForte(JavaThread *jt, frame fr, bool stop_at_java_call_stub); |
79 | void forte_next(); |
80 | }; |
81 | |
82 | |
83 | static bool is_decipherable_compiled_frame(JavaThread* thread, frame* fr, CompiledMethod* nm); |
84 | static bool is_decipherable_interpreted_frame(JavaThread* thread, |
85 | frame* fr, |
86 | Method** method_p, |
87 | int* bci_p); |
88 | |
89 | |
90 | |
91 | |
92 | vframeStreamForte::vframeStreamForte(JavaThread *jt, |
93 | frame fr, |
94 | bool stop_at_java_call_stub) : vframeStreamCommon(jt) { |
95 | |
96 | _stop_at_java_call_stub = stop_at_java_call_stub; |
97 | _frame = fr; |
98 | |
99 | // We must always have a valid frame to start filling |
100 | |
101 | bool filled_in = fill_from_frame(); |
102 | |
103 | assert(filled_in, "invariant" ); |
104 | |
105 | } |
106 | |
107 | |
108 | // Solaris SPARC Compiler1 needs an additional check on the grandparent |
109 | // of the top_frame when the parent of the top_frame is interpreted and |
110 | // the grandparent is compiled. However, in this method we do not know |
111 | // the relationship of the current _frame relative to the top_frame so |
112 | // we implement a more broad sanity check. When the previous callee is |
113 | // interpreted and the current sender is compiled, we verify that the |
114 | // current sender is also walkable. If it is not walkable, then we mark |
115 | // the current vframeStream as at the end. |
116 | void vframeStreamForte::forte_next() { |
117 | // handle frames with inlining |
118 | if (_mode == compiled_mode && |
119 | vframeStreamCommon::fill_in_compiled_inlined_sender()) { |
120 | return; |
121 | } |
122 | |
123 | // handle general case |
124 | |
125 | int loop_count = 0; |
126 | int loop_max = MaxJavaStackTraceDepth * 2; |
127 | |
128 | |
129 | do { |
130 | |
131 | loop_count++; |
132 | |
133 | // By the time we get here we should never see unsafe but better |
134 | // safe then segv'd |
135 | |
136 | if ((loop_max != 0 && loop_count > loop_max) || !_frame.safe_for_sender(_thread)) { |
137 | _mode = at_end_mode; |
138 | return; |
139 | } |
140 | |
141 | _frame = _frame.sender(&_reg_map); |
142 | |
143 | } while (!fill_from_frame()); |
144 | } |
145 | |
146 | // Determine if 'fr' is a decipherable compiled frame. We are already |
147 | // assured that fr is for a java compiled method. |
148 | |
149 | static bool is_decipherable_compiled_frame(JavaThread* thread, frame* fr, CompiledMethod* nm) { |
150 | assert(nm->is_java_method(), "invariant" ); |
151 | |
152 | if (thread->has_last_Java_frame() && thread->last_Java_pc() == fr->pc()) { |
153 | // We're stopped at a call into the JVM so look for a PcDesc with |
154 | // the actual pc reported by the frame. |
155 | PcDesc* pc_desc = nm->pc_desc_at(fr->pc()); |
156 | |
157 | // Did we find a useful PcDesc? |
158 | if (pc_desc != NULL && |
159 | pc_desc->scope_decode_offset() != DebugInformationRecorder::serialized_null) { |
160 | return true; |
161 | } |
162 | } |
163 | |
164 | // We're at some random pc in the compiled method so search for the PcDesc |
165 | // whose pc is greater than the current PC. It's done this way |
166 | // because the extra PcDescs that are recorded for improved debug |
167 | // info record the end of the region covered by the ScopeDesc |
168 | // instead of the beginning. |
169 | PcDesc* pc_desc = nm->pc_desc_near(fr->pc() + 1); |
170 | |
171 | // Now do we have a useful PcDesc? |
172 | if (pc_desc == NULL || |
173 | pc_desc->scope_decode_offset() == DebugInformationRecorder::serialized_null) { |
174 | // No debug information is available for this PC. |
175 | // |
176 | // vframeStreamCommon::fill_from_frame() will decode the frame depending |
177 | // on the state of the thread. |
178 | // |
179 | // Case #1: If the thread is in Java (state == _thread_in_Java), then |
180 | // the vframeStreamCommon object will be filled as if the frame were a native |
181 | // compiled frame. Therefore, no debug information is needed. |
182 | // |
183 | // Case #2: If the thread is in any other state, then two steps will be performed: |
184 | // - if asserts are enabled, found_bad_method_frame() will be called and |
185 | // the assert in found_bad_method_frame() will be triggered; |
186 | // - if asserts are disabled, the vframeStreamCommon object will be filled |
187 | // as if it were a native compiled frame. |
188 | // |
189 | // Case (2) is similar to the way interpreter frames are processed in |
190 | // vframeStreamCommon::fill_from_interpreter_frame in case no valid BCI |
191 | // was found for an interpreted frame. If asserts are enabled, the assert |
192 | // in found_bad_method_frame() will be triggered. If asserts are disabled, |
193 | // the vframeStreamCommon object will be filled afterwards as if the |
194 | // interpreter were at the point of entering into the method. |
195 | return false; |
196 | } |
197 | |
198 | // This PcDesc is useful however we must adjust the frame's pc |
199 | // so that the vframeStream lookups will use this same pc |
200 | fr->set_pc(pc_desc->real_pc(nm)); |
201 | return true; |
202 | } |
203 | |
204 | |
205 | // Determine if 'fr' is a walkable interpreted frame. Returns false |
206 | // if it is not. *method_p, and *bci_p are not set when false is |
207 | // returned. *method_p is non-NULL if frame was executing a Java |
208 | // method. *bci_p is != -1 if a valid BCI in the Java method could |
209 | // be found. |
210 | // Note: this method returns true when a valid Java method is found |
211 | // even if a valid BCI cannot be found. |
212 | |
213 | static bool is_decipherable_interpreted_frame(JavaThread* thread, |
214 | frame* fr, |
215 | Method** method_p, |
216 | int* bci_p) { |
217 | assert(fr->is_interpreted_frame(), "just checking" ); |
218 | |
219 | // top frame is an interpreted frame |
220 | // check if it is walkable (i.e. valid Method* and valid bci) |
221 | |
222 | // Because we may be racing a gc thread the method and/or bci |
223 | // of a valid interpreter frame may look bad causing us to |
224 | // fail the is_interpreted_frame_valid test. If the thread |
225 | // is in any of the following states we are assured that the |
226 | // frame is in fact valid and we must have hit the race. |
227 | |
228 | JavaThreadState state = thread->thread_state(); |
229 | bool known_valid = (state == _thread_in_native || |
230 | state == _thread_in_vm || |
231 | state == _thread_blocked ); |
232 | |
233 | if (known_valid || fr->is_interpreted_frame_valid(thread)) { |
234 | |
235 | // The frame code should completely validate the frame so that |
236 | // references to Method* and bci are completely safe to access |
237 | // If they aren't the frame code should be fixed not this |
238 | // code. However since gc isn't locked out the values could be |
239 | // stale. This is a race we can never completely win since we can't |
240 | // lock out gc so do one last check after retrieving their values |
241 | // from the frame for additional safety |
242 | |
243 | Method* method = fr->interpreter_frame_method(); |
244 | |
245 | // We've at least found a method. |
246 | // NOTE: there is something to be said for the approach that |
247 | // if we don't find a valid bci then the method is not likely |
248 | // a valid method. Then again we may have caught an interpreter |
249 | // frame in the middle of construction and the bci field is |
250 | // not yet valid. |
251 | if (!Method::is_valid_method(method)) return false; |
252 | *method_p = method; // If the Method* found is invalid, it is |
253 | // ignored by forte_fill_call_trace_given_top(). |
254 | // So set method_p only if the Method is valid. |
255 | |
256 | address bcp = fr->interpreter_frame_bcp(); |
257 | int bci = method->validate_bci_from_bcp(bcp); |
258 | |
259 | // note: bci is set to -1 if not a valid bci |
260 | *bci_p = bci; |
261 | return true; |
262 | } |
263 | |
264 | return false; |
265 | } |
266 | |
267 | |
268 | // Determine if a Java frame can be found starting with the frame 'fr'. |
269 | // |
270 | // Check the return value of find_initial_Java_frame and the value of |
271 | // 'method_p' to decide on how use the results returned by this method. |
272 | // |
273 | // If 'method_p' is not NULL, an initial Java frame has been found and |
274 | // the stack can be walked starting from that initial frame. In this case, |
275 | // 'method_p' points to the Method that the initial frame belongs to and |
276 | // the initial Java frame is returned in initial_frame_p. |
277 | // |
278 | // find_initial_Java_frame() returns true if a Method has been found (i.e., |
279 | // 'method_p' is not NULL) and the initial frame that belongs to that Method |
280 | // is decipherable. |
281 | // |
282 | // A frame is considered to be decipherable: |
283 | // |
284 | // - if the frame is a compiled frame and a PCDesc is available; |
285 | // |
286 | // - if the frame is an interpreter frame that is valid or the thread is |
287 | // state (_thread_in_native || state == _thread_in_vm || state == _thread_blocked). |
288 | // |
289 | // Note that find_initial_Java_frame() can return false even if an initial |
290 | // Java method was found (e.g., there is no PCDesc available for the method). |
291 | // |
292 | // If 'method_p' is NULL, it was not possible to find a Java frame when |
293 | // walking the stack starting from 'fr'. In this case find_initial_Java_frame |
294 | // returns false. |
295 | |
296 | static bool find_initial_Java_frame(JavaThread* thread, |
297 | frame* fr, |
298 | frame* initial_frame_p, |
299 | Method** method_p, |
300 | int* bci_p) { |
301 | |
302 | // It is possible that for a frame containing a compiled method |
303 | // we can capture the method but no bci. If we get no |
304 | // bci the frame isn't walkable but the method is usable. |
305 | // Therefore we init the returned Method* to NULL so the |
306 | // caller can make the distinction. |
307 | |
308 | *method_p = NULL; |
309 | |
310 | // On the initial call to this method the frame we get may not be |
311 | // recognizable to us. This should only happen if we are in a JRT_LEAF |
312 | // or something called by a JRT_LEAF method. |
313 | |
314 | frame candidate = *fr; |
315 | |
316 | // If the starting frame we were given has no codeBlob associated with |
317 | // it see if we can find such a frame because only frames with codeBlobs |
318 | // are possible Java frames. |
319 | |
320 | if (fr->cb() == NULL) { |
321 | |
322 | // See if we can find a useful frame |
323 | int loop_count; |
324 | int loop_max = MaxJavaStackTraceDepth * 2; |
325 | RegisterMap map(thread, false); |
326 | |
327 | for (loop_count = 0; loop_max == 0 || loop_count < loop_max; loop_count++) { |
328 | if (!candidate.safe_for_sender(thread)) return false; |
329 | candidate = candidate.sender(&map); |
330 | if (candidate.cb() != NULL) break; |
331 | } |
332 | if (candidate.cb() == NULL) return false; |
333 | } |
334 | |
335 | // We have a frame known to be in the codeCache |
336 | // We will hopefully be able to figure out something to do with it. |
337 | int loop_count; |
338 | int loop_max = MaxJavaStackTraceDepth * 2; |
339 | RegisterMap map(thread, false); |
340 | |
341 | for (loop_count = 0; loop_max == 0 || loop_count < loop_max; loop_count++) { |
342 | |
343 | if (candidate.is_entry_frame()) { |
344 | // jcw is NULL if the java call wrapper couldn't be found |
345 | JavaCallWrapper *jcw = candidate.entry_frame_call_wrapper_if_safe(thread); |
346 | // If initial frame is frame from StubGenerator and there is no |
347 | // previous anchor, there are no java frames associated with a method |
348 | if (jcw == NULL || jcw->is_first_frame()) { |
349 | return false; |
350 | } |
351 | } |
352 | |
353 | if (candidate.is_interpreted_frame()) { |
354 | if (is_decipherable_interpreted_frame(thread, &candidate, method_p, bci_p)) { |
355 | *initial_frame_p = candidate; |
356 | return true; |
357 | } |
358 | |
359 | // Hopefully we got some data |
360 | return false; |
361 | } |
362 | |
363 | if (candidate.cb()->is_compiled()) { |
364 | |
365 | CompiledMethod* nm = candidate.cb()->as_compiled_method(); |
366 | *method_p = nm->method(); |
367 | |
368 | // If the frame is not decipherable, then the value of -1 |
369 | // for the BCI is used to signal that no BCI is available. |
370 | // Furthermore, the method returns false in this case. |
371 | // |
372 | // If a decipherable frame is available, the BCI value will |
373 | // not be used. |
374 | |
375 | *bci_p = -1; |
376 | |
377 | *initial_frame_p = candidate; |
378 | |
379 | // Native wrapper code is trivial to decode by vframeStream |
380 | |
381 | if (nm->is_native_method()) return true; |
382 | |
383 | // If the frame is not decipherable, then a PC was found |
384 | // that does not have a PCDesc from which a BCI can be obtained. |
385 | // Nevertheless, a Method was found. |
386 | |
387 | if (!is_decipherable_compiled_frame(thread, &candidate, nm)) { |
388 | return false; |
389 | } |
390 | |
391 | // is_decipherable_compiled_frame may modify candidate's pc |
392 | *initial_frame_p = candidate; |
393 | |
394 | assert(nm->pc_desc_at(candidate.pc()) != NULL, "debug information must be available if the frame is decipherable" ); |
395 | |
396 | return true; |
397 | } |
398 | |
399 | // Must be some stub frame that we don't care about |
400 | |
401 | if (!candidate.safe_for_sender(thread)) return false; |
402 | candidate = candidate.sender(&map); |
403 | |
404 | // If it isn't in the code cache something is wrong |
405 | // since once we find a frame in the code cache they |
406 | // all should be there. |
407 | |
408 | if (candidate.cb() == NULL) return false; |
409 | |
410 | } |
411 | |
412 | return false; |
413 | |
414 | } |
415 | |
416 | static void forte_fill_call_trace_given_top(JavaThread* thd, |
417 | ASGCT_CallTrace* trace, |
418 | int depth, |
419 | frame top_frame) { |
420 | NoHandleMark nhm; |
421 | |
422 | frame initial_Java_frame; |
423 | Method* method; |
424 | int bci = -1; // assume BCI is not available for method |
425 | // update with correct information if available |
426 | int count; |
427 | |
428 | count = 0; |
429 | assert(trace->frames != NULL, "trace->frames must be non-NULL" ); |
430 | |
431 | // Walk the stack starting from 'top_frame' and search for an initial Java frame. |
432 | find_initial_Java_frame(thd, &top_frame, &initial_Java_frame, &method, &bci); |
433 | |
434 | // Check if a Java Method has been found. |
435 | if (method == NULL) return; |
436 | |
437 | if (!Method::is_valid_method(method)) { |
438 | trace->num_frames = ticks_GC_active; // -2 |
439 | return; |
440 | } |
441 | |
442 | vframeStreamForte st(thd, initial_Java_frame, false); |
443 | |
444 | for (; !st.at_end() && count < depth; st.forte_next(), count++) { |
445 | bci = st.bci(); |
446 | method = st.method(); |
447 | |
448 | if (!Method::is_valid_method(method)) { |
449 | // we throw away everything we've gathered in this sample since |
450 | // none of it is safe |
451 | trace->num_frames = ticks_GC_active; // -2 |
452 | return; |
453 | } |
454 | |
455 | trace->frames[count].method_id = method->find_jmethod_id_or_null(); |
456 | if (!method->is_native()) { |
457 | trace->frames[count].lineno = bci; |
458 | } else { |
459 | trace->frames[count].lineno = -3; |
460 | } |
461 | } |
462 | trace->num_frames = count; |
463 | return; |
464 | } |
465 | |
466 | |
467 | // Forte Analyzer AsyncGetCallTrace() entry point. Currently supported |
468 | // on Linux X86, Solaris SPARC and Solaris X86. |
469 | // |
470 | // Async-safe version of GetCallTrace being called from a signal handler |
471 | // when a LWP gets interrupted by SIGPROF but the stack traces are filled |
472 | // with different content (see below). |
473 | // |
474 | // This function must only be called when JVM/TI |
475 | // CLASS_LOAD events have been enabled since agent startup. The enabled |
476 | // event will cause the jmethodIDs to be allocated at class load time. |
477 | // The jmethodIDs cannot be allocated in a signal handler because locks |
478 | // cannot be grabbed in a signal handler safely. |
479 | // |
480 | // void (*AsyncGetCallTrace)(ASGCT_CallTrace *trace, jint depth, void* ucontext) |
481 | // |
482 | // Called by the profiler to obtain the current method call stack trace for |
483 | // a given thread. The thread is identified by the env_id field in the |
484 | // ASGCT_CallTrace structure. The profiler agent should allocate a ASGCT_CallTrace |
485 | // structure with enough memory for the requested stack depth. The VM fills in |
486 | // the frames buffer and the num_frames field. |
487 | // |
488 | // Arguments: |
489 | // |
490 | // trace - trace data structure to be filled by the VM. |
491 | // depth - depth of the call stack trace. |
492 | // ucontext - ucontext_t of the LWP |
493 | // |
494 | // ASGCT_CallTrace: |
495 | // typedef struct { |
496 | // JNIEnv *env_id; |
497 | // jint num_frames; |
498 | // ASGCT_CallFrame *frames; |
499 | // } ASGCT_CallTrace; |
500 | // |
501 | // Fields: |
502 | // env_id - ID of thread which executed this trace. |
503 | // num_frames - number of frames in the trace. |
504 | // (< 0 indicates the frame is not walkable). |
505 | // frames - the ASGCT_CallFrames that make up this trace. Callee followed by callers. |
506 | // |
507 | // ASGCT_CallFrame: |
508 | // typedef struct { |
509 | // jint lineno; |
510 | // jmethodID method_id; |
511 | // } ASGCT_CallFrame; |
512 | // |
513 | // Fields: |
514 | // 1) For Java frame (interpreted and compiled), |
515 | // lineno - bci of the method being executed or -1 if bci is not available |
516 | // method_id - jmethodID of the method being executed |
517 | // 2) For native method |
518 | // lineno - (-3) |
519 | // method_id - jmethodID of the method being executed |
520 | |
521 | extern "C" { |
522 | JNIEXPORT |
523 | void AsyncGetCallTrace(ASGCT_CallTrace *trace, jint depth, void* ucontext) { |
524 | JavaThread* thread; |
525 | |
526 | if (trace->env_id == NULL || |
527 | (thread = JavaThread::thread_from_jni_environment(trace->env_id)) == NULL || |
528 | thread->is_exiting()) { |
529 | |
530 | // bad env_id, thread has exited or thread is exiting |
531 | trace->num_frames = ticks_thread_exit; // -8 |
532 | return; |
533 | } |
534 | |
535 | if (thread->in_deopt_handler()) { |
536 | // thread is in the deoptimization handler so return no frames |
537 | trace->num_frames = ticks_deopt; // -9 |
538 | return; |
539 | } |
540 | |
541 | assert(JavaThread::current() == thread, |
542 | "AsyncGetCallTrace must be called by the current interrupted thread" ); |
543 | |
544 | if (!JvmtiExport::should_post_class_load()) { |
545 | trace->num_frames = ticks_no_class_load; // -1 |
546 | return; |
547 | } |
548 | |
549 | if (Universe::heap()->is_gc_active()) { |
550 | trace->num_frames = ticks_GC_active; // -2 |
551 | return; |
552 | } |
553 | |
554 | switch (thread->thread_state()) { |
555 | case _thread_new: |
556 | case _thread_uninitialized: |
557 | case _thread_new_trans: |
558 | // We found the thread on the threads list above, but it is too |
559 | // young to be useful so return that there are no Java frames. |
560 | trace->num_frames = 0; |
561 | break; |
562 | case _thread_in_native: |
563 | case _thread_in_native_trans: |
564 | case _thread_blocked: |
565 | case _thread_blocked_trans: |
566 | case _thread_in_vm: |
567 | case _thread_in_vm_trans: |
568 | { |
569 | frame fr; |
570 | |
571 | // param isInJava == false - indicate we aren't in Java code |
572 | if (!thread->pd_get_top_frame_for_signal_handler(&fr, ucontext, false)) { |
573 | trace->num_frames = ticks_unknown_not_Java; // -3 unknown frame |
574 | } else { |
575 | if (!thread->has_last_Java_frame()) { |
576 | trace->num_frames = 0; // No Java frames |
577 | } else { |
578 | trace->num_frames = ticks_not_walkable_not_Java; // -4 non walkable frame by default |
579 | forte_fill_call_trace_given_top(thread, trace, depth, fr); |
580 | |
581 | // This assert would seem to be valid but it is not. |
582 | // It would be valid if we weren't possibly racing a gc |
583 | // thread. A gc thread can make a valid interpreted frame |
584 | // look invalid. It's a small window but it does happen. |
585 | // The assert is left here commented out as a reminder. |
586 | // assert(trace->num_frames != ticks_not_walkable_not_Java, "should always be walkable"); |
587 | |
588 | } |
589 | } |
590 | } |
591 | break; |
592 | case _thread_in_Java: |
593 | case _thread_in_Java_trans: |
594 | { |
595 | frame fr; |
596 | |
597 | // param isInJava == true - indicate we are in Java code |
598 | if (!thread->pd_get_top_frame_for_signal_handler(&fr, ucontext, true)) { |
599 | trace->num_frames = ticks_unknown_Java; // -5 unknown frame |
600 | } else { |
601 | trace->num_frames = ticks_not_walkable_Java; // -6, non walkable frame by default |
602 | forte_fill_call_trace_given_top(thread, trace, depth, fr); |
603 | } |
604 | } |
605 | break; |
606 | default: |
607 | // Unknown thread state |
608 | trace->num_frames = ticks_unknown_state; // -7 |
609 | break; |
610 | } |
611 | } |
612 | |
613 | |
614 | #ifndef _WINDOWS |
615 | // Support for the Forte(TM) Peformance Tools collector. |
616 | // |
617 | // The method prototype is derived from libcollector.h. For more |
618 | // information, please see the libcollect man page. |
619 | |
620 | // Method to let libcollector know about a dynamically loaded function. |
621 | // Because it is weakly bound, the calls become NOP's when the library |
622 | // isn't present. |
623 | #ifdef __APPLE__ |
624 | // XXXDARWIN: Link errors occur even when __attribute__((weak_import)) |
625 | // is added |
626 | #define collector_func_load(x0,x1,x2,x3,x4,x5,x6) ((void) 0) |
627 | #else |
628 | void collector_func_load(char* name, |
629 | void* null_argument_1, |
630 | void* null_argument_2, |
631 | void *vaddr, |
632 | int size, |
633 | int zero_argument, |
634 | void* null_argument_3); |
635 | #pragma weak collector_func_load |
636 | #define collector_func_load(x0,x1,x2,x3,x4,x5,x6) \ |
637 | ( collector_func_load ? collector_func_load(x0,x1,x2,x3,x4,x5,x6),(void)0 : (void)0 ) |
638 | #endif // __APPLE__ |
639 | #endif // !_WINDOWS |
640 | |
641 | } // end extern "C" |
642 | #endif // !IA64 |
643 | |
644 | void Forte::register_stub(const char* name, address start, address end) { |
645 | #if !defined(_WINDOWS) && !defined(IA64) |
646 | assert(pointer_delta(end, start, sizeof(jbyte)) < INT_MAX, |
647 | "Code size exceeds maximum range" ); |
648 | |
649 | collector_func_load((char*)name, NULL, NULL, start, |
650 | pointer_delta(end, start, sizeof(jbyte)), 0, NULL); |
651 | #endif // !_WINDOWS && !IA64 |
652 | } |
653 | |
654 | #else // INCLUDE_JVMTI |
655 | extern "C" { |
656 | JNIEXPORT |
657 | void AsyncGetCallTrace(ASGCT_CallTrace *trace, jint depth, void* ucontext) { |
658 | trace->num_frames = ticks_no_class_load; // -1 |
659 | } |
660 | } |
661 | #endif // INCLUDE_JVMTI |
662 | |