Mercurial > hg > truffle
diff src/share/vm/prims/forte.cpp @ 0:a61af66fc99e jdk7-b24
Initial load
author | duke |
---|---|
date | Sat, 01 Dec 2007 00:00:00 +0000 |
parents | |
children | 93b6525e3b82 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/prims/forte.cpp Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,895 @@ +/* + * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +# include "incls/_precompiled.incl" +# include "incls/_forte.cpp.incl" + + +//------------------------------------------------------- + +// Native interfaces for use by Forte tools. + + +#ifndef IA64 + +class vframeStreamForte : public vframeStreamCommon { + public: + // constructor that starts with sender of frame fr (top_frame) + vframeStreamForte(JavaThread *jt, frame fr, bool stop_at_java_call_stub); + void forte_next(); +}; + + +static void forte_is_walkable_compiled_frame(frame* fr, RegisterMap* map, + bool* is_compiled_p, bool* is_walkable_p); +static bool forte_is_walkable_interpreted_frame(frame* fr, + methodOop* method_p, int* bci_p); + + +// A Forte specific version of frame:safe_for_sender(). +static bool forte_safe_for_sender(frame* fr, JavaThread *thread) { + bool ret_value = false; // be pessimistic + +#ifdef COMPILER2 +#if defined(IA32) || defined(AMD64) + { + // This check is the same as the standard safe_for_sender() + // on IA32 or AMD64 except that NULL FP values are tolerated + // for C2. + address sp = (address)fr->sp(); + address fp = (address)fr->fp(); + ret_value = sp != NULL && sp <= thread->stack_base() && + sp >= thread->stack_base() - thread->stack_size() && + (fp == NULL || (fp <= thread->stack_base() && + fp >= thread->stack_base() - thread->stack_size())); + + // We used to use standard safe_for_sender() when we are supposed + // to be executing Java code. However, that prevents us from + // walking some intrinsic stacks so now we have to be more refined. + // If we passed the above check and we have a NULL frame pointer + // and we are supposed to be executing Java code, then we have a + // couple of more checks to make. + if (ret_value && fp == NULL && (thread->thread_state() == _thread_in_Java + || thread->thread_state() == _thread_in_Java_trans)) { + + if (fr->is_interpreted_frame()) { + // interpreted frames don't really have a NULL frame pointer + return false; + } else if (CodeCache::find_blob(fr->pc()) == NULL) { + // the NULL frame pointer should be associated with generated code + return false; + } + } + } + +#else // !(IA32 || AMD64) + ret_value = fr->safe_for_sender(thread); +#endif // IA32 || AMD64 + +#else // !COMPILER2 + ret_value = fr->safe_for_sender(thread); +#endif // COMPILER2 + + if (!ret_value) { + return ret_value; // not safe, nothing more to do + } + + address sp1; + +#ifdef SPARC + // On Solaris SPARC, when a compiler frame has an interpreted callee + // the _interpreter_sp_adjustment field contains the adjustment to + // this frame's SP made by that interpreted callee. + // For AsyncGetCallTrace(), we need to verify that the resulting SP + // is valid for the specified thread's stack. + sp1 = (address)fr->sp(); + address sp2 = (address)fr->unextended_sp(); + + // If the second SP is NULL, then the _interpreter_sp_adjustment + // field simply adjusts this frame's SP to NULL and the frame is + // not safe. This strange value can be set in the frame constructor + // when our peek into the interpreted callee's adjusted value for + // this frame's SP finds a NULL. This can happen when SIGPROF + // catches us while we are creating the interpreter frame. + // + if (sp2 == NULL || + + // If the two SPs are different, then _interpreter_sp_adjustment + // is non-zero and we need to validate the second SP. We invert + // the range check from frame::safe_for_sender() and bail out + // if the second SP is not safe. + (sp1 != sp2 && !(sp2 <= thread->stack_base() + && sp2 >= (thread->stack_base() - thread->stack_size())))) { + return false; + } +#endif // SPARC + + if (fr->is_entry_frame()) { + // This frame thinks it is an entry frame; we need to validate + // the JavaCallWrapper pointer. + // Note: frame::entry_frame_is_first() assumes that the + // JavaCallWrapper has a non-NULL _anchor field. We don't + // check that here (yet) since we've never seen a failure + // due to a NULL _anchor field. + // Update: Originally this check was done only for SPARC. However, + // this failure has now been seen on C2 C86. I have no reason to + // believe that this is not a general issue so I'm enabling the + // check for all compilers on all supported platforms. +#ifdef COMPILER2 +#if defined(IA32) || defined(AMD64) + if (fr->fp() == NULL) { + // C2 X86 allows NULL frame pointers, but if we have one then + // we cannot call entry_frame_call_wrapper(). + return false; + } +#endif // IA32 || AMD64 +#endif // COMPILER2 + + sp1 = (address)fr->entry_frame_call_wrapper(); + // We invert the range check from frame::safe_for_sender() and + // bail out if the JavaCallWrapper * is not safe. + if (!(sp1 <= thread->stack_base() + && sp1 >= (thread->stack_base() - thread->stack_size()))) { + return false; + } + } + + return ret_value; +} + + +// Unknown compiled frames have caused assertion failures on Solaris +// X86. This code also detects unknown compiled frames on Solaris +// SPARC, but no assertion failures have been observed. However, I'm +// paranoid so I'm enabling this code whenever we have a compiler. +// +// Returns true if the specified frame is an unknown compiled frame +// and false otherwise. +static bool is_unknown_compiled_frame(frame* fr, JavaThread *thread) { + bool ret_value = false; // be optimistic + + // This failure mode only occurs when the thread is in state + // _thread_in_Java so we are okay for this check for any other + // thread state. + // + // Note: _thread_in_Java does not always mean that the thread + // is executing Java code. AsyncGetCallTrace() has caught + // threads executing in JRT_LEAF() routines when the state + // will also be _thread_in_Java. + if (thread->thread_state() != _thread_in_Java) { + return ret_value; + } + + // This failure mode only occurs with compiled frames so we are + // okay for this check for both entry and interpreted frames. + if (fr->is_entry_frame() || fr->is_interpreted_frame()) { + return ret_value; + } + + // This failure mode only occurs when the compiled frame's PC + // is in the code cache so we are okay for this check if the + // PC is not in the code cache. + CodeBlob* cb = CodeCache::find_blob(fr->pc()); + if (cb == NULL) { + return ret_value; + } + + // We have compiled code in the code cache so it is time for + // the final check: let's see if any frame type is set + ret_value = !( + // is_entry_frame() is checked above + // testers that are a subset of is_entry_frame(): + // is_first_frame() + fr->is_java_frame() + // testers that are a subset of is_java_frame(): + // is_interpreted_frame() + // is_compiled_frame() + || fr->is_native_frame() + || fr->is_runtime_frame() + || fr->is_safepoint_blob_frame() + ); + + // If there is no frame type set, then we have an unknown compiled + // frame and sender() should not be called on it. + + return ret_value; +} + +#define DebugNonSafepoints_IS_CLEARED \ + (!FLAG_IS_DEFAULT(DebugNonSafepoints) && !DebugNonSafepoints) + +// if -XX:-DebugNonSafepoints, then top-frame will be skipped +vframeStreamForte::vframeStreamForte(JavaThread *jt, frame fr, + bool stop_at_java_call_stub) : vframeStreamCommon(jt) { + _stop_at_java_call_stub = stop_at_java_call_stub; + + if (!DebugNonSafepoints_IS_CLEARED) { + // decode the top frame fully + // (usual case, if JVMTI is enabled) + _frame = fr; + } else { + // skip top frame, as it may not be at safepoint + // For AsyncGetCallTrace(), we extracted as much info from the top + // frame as we could in forte_is_walkable_frame(). We also verified + // forte_safe_for_sender() so this sender() call is safe. + _frame = fr.sender(&_reg_map); + } + + if (jt->thread_state() == _thread_in_Java && !fr.is_first_frame()) { + bool sender_check = false; // assume sender is not safe + + if (forte_safe_for_sender(&_frame, jt)) { + // If the initial sender frame is safe, then continue on with other + // checks. The unsafe sender frame has been seen on Solaris X86 + // with both Compiler1 and Compiler2. It has not been seen on + // Solaris SPARC, but seems like a good sanity check to have + // anyway. + + // SIGPROF caught us in Java code and the current frame is not the + // first frame so we should sanity check the sender frame. It is + // possible for SIGPROF to catch us in the middle of making a call. + // When that happens the current frame is actually a combination of + // the real sender and some of the new call's info. We can't find + // the real sender with such a current frame and things can get + // confused. + // + // This sanity check has caught problems with the sender frame on + // Solaris SPARC. So far Solaris X86 has not had a failure here. + sender_check = _frame.is_entry_frame() + // testers that are a subset of is_entry_frame(): + // is_first_frame() + || _frame.is_java_frame() + // testers that are a subset of is_java_frame(): + // is_interpreted_frame() + // is_compiled_frame() + || _frame.is_native_frame() + || _frame.is_runtime_frame() + || _frame.is_safepoint_blob_frame() + ; + + // We need an additional sanity check on an initial interpreted + // sender frame. This interpreted frame needs to be both walkable + // and have a valid BCI. This is yet another variant of SIGPROF + // catching us in the middle of making a call. + if (sender_check && _frame.is_interpreted_frame()) { + methodOop method = NULL; + int bci = -1; + + if (!forte_is_walkable_interpreted_frame(&_frame, &method, &bci) + || bci == -1) { + sender_check = false; + } + } + + // We need an additional sanity check on an initial compiled + // sender frame. This compiled frame also needs to be walkable. + // This is yet another variant of SIGPROF catching us in the + // middle of making a call. + if (sender_check && !_frame.is_interpreted_frame()) { + bool is_compiled, is_walkable; + + forte_is_walkable_compiled_frame(&_frame, &_reg_map, + &is_compiled, &is_walkable); + if (is_compiled && !is_walkable) { + sender_check = false; + } + } + } + + if (!sender_check) { + // nothing else to try if we can't recognize the sender + _mode = at_end_mode; + return; + } + } + + int loop_count = 0; + int loop_max = MaxJavaStackTraceDepth * 2; + + while (!fill_from_frame()) { + _frame = _frame.sender(&_reg_map); + +#ifdef COMPILER2 +#if defined(IA32) || defined(AMD64) + // Stress testing on C2 X86 has shown a periodic problem with + // the sender() call below. The initial _frame that we have on + // entry to the loop has already passed forte_safe_for_sender() + // so we only check frames after it. + if (!forte_safe_for_sender(&_frame, _thread)) { + _mode = at_end_mode; + return; + } +#endif // IA32 || AMD64 +#endif // COMPILER2 + + if (++loop_count >= loop_max) { + // We have looped more than twice the number of possible + // Java frames. This indicates that we are trying to walk + // a stack that is in the middle of being constructed and + // it is self referential. + _mode = at_end_mode; + return; + } + } +} + + +// Solaris SPARC Compiler1 needs an additional check on the grandparent +// of the top_frame when the parent of the top_frame is interpreted and +// the grandparent is compiled. However, in this method we do not know +// the relationship of the current _frame relative to the top_frame so +// we implement a more broad sanity check. When the previous callee is +// interpreted and the current sender is compiled, we verify that the +// current sender is also walkable. If it is not walkable, then we mark +// the current vframeStream as at the end. +void vframeStreamForte::forte_next() { + // handle frames with inlining + if (_mode == compiled_mode && + vframeStreamCommon::fill_in_compiled_inlined_sender()) { + return; + } + + // handle general case + + int loop_count = 0; + int loop_max = MaxJavaStackTraceDepth * 2; + + + do { + +#if defined(COMPILER1) && defined(SPARC) + bool prevIsInterpreted = _frame.is_interpreted_frame(); +#endif // COMPILER1 && SPARC + + _frame = _frame.sender(&_reg_map); + + if (!forte_safe_for_sender(&_frame, _thread)) { + _mode = at_end_mode; + return; + } + +#if defined(COMPILER1) && defined(SPARC) + if (prevIsInterpreted) { + // previous callee was interpreted and may require a special check + if (_frame.is_compiled_frame() && _frame.cb()->is_compiled_by_c1()) { + // compiled sender called interpreted callee so need one more check + bool is_compiled, is_walkable; + + // sanity check the compiled sender frame + forte_is_walkable_compiled_frame(&_frame, &_reg_map, + &is_compiled, &is_walkable); + assert(is_compiled, "sanity check"); + if (!is_walkable) { + // compiled sender frame is not walkable so bail out + _mode = at_end_mode; + return; + } + } + } +#endif // COMPILER1 && SPARC + + if (++loop_count >= loop_max) { + // We have looped more than twice the number of possible + // Java frames. This indicates that we are trying to walk + // a stack that is in the middle of being constructed and + // it is self referential. + _mode = at_end_mode; + return; + } + } while (!fill_from_frame()); +} + +// Determine if 'fr' is a walkable, compiled frame. +// *is_compiled_p is set to true if the frame is compiled and if it +// is, then *is_walkable_p is set to true if it is also walkable. +static void forte_is_walkable_compiled_frame(frame* fr, RegisterMap* map, + bool* is_compiled_p, bool* is_walkable_p) { + + *is_compiled_p = false; + *is_walkable_p = false; + + CodeBlob* cb = CodeCache::find_blob(fr->pc()); + if (cb != NULL && + cb->is_nmethod() && + ((nmethod*)cb)->is_java_method()) { + // frame is compiled and executing a Java method + *is_compiled_p = true; + + // Increment PC because the PcDesc we want is associated with + // the *end* of the instruction, and pc_desc_near searches + // forward to the first matching PC after the probe PC. + PcDesc* pc_desc = NULL; + if (!DebugNonSafepoints_IS_CLEARED) { + // usual case: look for any safepoint near the sampled PC + address probe_pc = fr->pc() + 1; + pc_desc = ((nmethod*) cb)->pc_desc_near(probe_pc); + } else { + // reduced functionality: only recognize PCs immediately after calls + pc_desc = ((nmethod*) cb)->pc_desc_at(fr->pc()); + } + if (pc_desc != NULL && (pc_desc->scope_decode_offset() + == DebugInformationRecorder::serialized_null)) { + pc_desc = NULL; + } + if (pc_desc != NULL) { + // it has a PcDesc so the frame is also walkable + *is_walkable_p = true; + if (!DebugNonSafepoints_IS_CLEARED) { + // Normalize the PC to the one associated exactly with + // this PcDesc, so that subsequent stack-walking queries + // need not be approximate: + fr->set_pc(pc_desc->real_pc((nmethod*) cb)); + } + } + // Implied else: this compiled frame has no PcDesc, i.e., contains + // a frameless stub such as C1 method exit, so it is not walkable. + } + // Implied else: this isn't a compiled frame so it isn't a + // walkable, compiled frame. +} + +// Determine if 'fr' is a walkable interpreted frame. Returns false +// if it is not. *method_p, and *bci_p are not set when false is +// returned. *method_p is non-NULL if frame was executing a Java +// method. *bci_p is != -1 if a valid BCI in the Java method could +// be found. +// Note: this method returns true when a valid Java method is found +// even if a valid BCI cannot be found. + +static bool forte_is_walkable_interpreted_frame(frame* fr, + methodOop* method_p, int* bci_p) { + assert(fr->is_interpreted_frame(), "just checking"); + + // top frame is an interpreted frame + // check if it is walkable (i.e. valid methodOop and valid bci) + if (fr->is_interpreted_frame_valid()) { + if (fr->fp() != NULL) { + // access address in order not to trigger asserts that + // are built in interpreter_frame_method function + methodOop method = *fr->interpreter_frame_method_addr(); + if (Universe::heap()->is_valid_method(method)) { + intptr_t bcx = fr->interpreter_frame_bcx(); + int bci = method->validate_bci_from_bcx(bcx); + // note: bci is set to -1 if not a valid bci + *method_p = method; + *bci_p = bci; + return true; + } + } + } + return false; +} + + +// Determine if 'fr' can be used to find a walkable frame. Returns +// false if a walkable frame cannot be found. *walkframe_p, *method_p, +// and *bci_p are not set when false is returned. Returns true if a +// walkable frame is returned via *walkframe_p. *method_p is non-NULL +// if the returned frame was executing a Java method. *bci_p is != -1 +// if a valid BCI in the Java method could be found. +// +// *walkframe_p will be used by vframeStreamForte as the initial +// frame for walking the stack. Currently the initial frame is +// skipped by vframeStreamForte because we inherited the logic from +// the vframeStream class. This needs to be revisited in the future. +static bool forte_is_walkable_frame(JavaThread* thread, frame* fr, + frame* walkframe_p, methodOop* method_p, int* bci_p) { + + if (!forte_safe_for_sender(fr, thread) + || is_unknown_compiled_frame(fr, thread) + ) { + // If the initial frame is not safe, then bail out. So far this + // has only been seen on Solaris X86 with Compiler2, but it seems + // like a great initial sanity check. + return false; + } + + if (fr->is_first_frame()) { + // If initial frame is frame from StubGenerator and there is no + // previous anchor, there are no java frames yet + return false; + } + + if (fr->is_interpreted_frame()) { + if (forte_is_walkable_interpreted_frame(fr, method_p, bci_p)) { + *walkframe_p = *fr; + return true; + } + return false; + } + + // At this point we have something other than a first frame or an + // interpreted frame. + + methodOop method = NULL; + frame candidate = *fr; + + // If we loop more than twice the number of possible Java + // frames, then this indicates that we are trying to walk + // a stack that is in the middle of being constructed and + // it is self referential. So far this problem has only + // been seen on Solaris X86 Compiler2, but it seems like + // a good robustness fix for all platforms. + + int loop_count; + int loop_max = MaxJavaStackTraceDepth * 2; + + for (loop_count = 0; loop_count < loop_max; loop_count++) { + // determine if the candidate frame is executing a Java method + if (CodeCache::contains(candidate.pc())) { + // candidate is a compiled frame or stub routine + CodeBlob* cb = CodeCache::find_blob(candidate.pc()); + + if (cb->is_nmethod()) { + method = ((nmethod *)cb)->method(); + } + } // end if CodeCache has our PC + + RegisterMap map(thread, false); + + // we have a Java frame that seems reasonable + if (method != NULL && candidate.is_java_frame() + && candidate.sp() != NULL && candidate.pc() != NULL) { + // we need to sanity check the candidate further + bool is_compiled, is_walkable; + + forte_is_walkable_compiled_frame(&candidate, &map, &is_compiled, + &is_walkable); + if (is_compiled) { + // At this point, we know we have a compiled Java frame with + // method information that we want to return. We don't check + // the is_walkable flag here because that flag pertains to + // vframeStreamForte work that is done after we are done here. + break; + } + } + + // At this point, the candidate doesn't work so try the sender. + + // For AsyncGetCallTrace() we cannot assume there is a sender + // for the initial frame. The initial forte_safe_for_sender() call + // and check for is_first_frame() is done on entry to this method. + candidate = candidate.sender(&map); + if (!forte_safe_for_sender(&candidate, thread)) { + +#ifdef COMPILER2 +#if defined(IA32) || defined(AMD64) + // C2 on X86 can use the ebp register as a general purpose register + // which can cause the candidate to fail theforte_safe_for_sender() + // above. We try one more time using a NULL frame pointer (fp). + + candidate = frame(candidate.sp(), NULL, candidate.pc()); + if (!forte_safe_for_sender(&candidate, thread)) { +#endif // IA32 || AMD64 +#endif // COMPILER2 + + return false; + +#ifdef COMPILER2 +#if defined(IA32) || defined(AMD64) + } // end forte_safe_for_sender retry with NULL fp +#endif // IA32 || AMD64 +#endif // COMPILER2 + + } // end first forte_safe_for_sender check + + if (candidate.is_first_frame() + || is_unknown_compiled_frame(&candidate, thread)) { + return false; + } + } // end for loop_count + + if (method == NULL) { + // If we didn't get any method info from the candidate, then + // we have nothing to return so bail out. + return false; + } + + *walkframe_p = candidate; + *method_p = method; + *bci_p = -1; + return true; +} + + +// call frame copied from old .h file and renamed +typedef struct { + jint lineno; // line number in the source file + jmethodID method_id; // method executed in this frame +} ASGCT_CallFrame; + +// call trace copied from old .h file and renamed +typedef struct { + JNIEnv *env_id; // Env where trace was recorded + jint num_frames; // number of frames in this trace + ASGCT_CallFrame *frames; // frames +} ASGCT_CallTrace; + +static void forte_fill_call_trace_given_top(JavaThread* thd, + ASGCT_CallTrace* trace, int depth, frame top_frame) { + NoHandleMark nhm; + + frame walkframe; + methodOop method; + int bci; + int count; + + count = 0; + assert(trace->frames != NULL, "trace->frames must be non-NULL"); + + if (!forte_is_walkable_frame(thd, &top_frame, &walkframe, &method, &bci)) { + // return if no walkable frame is found + return; + } + + CollectedHeap* ch = Universe::heap(); + + if (method != NULL) { + // The method is not stored GC safe so see if GC became active + // after we entered AsyncGetCallTrace() and before we try to + // use the methodOop. + // Yes, there is still a window after this check and before + // we use methodOop below, but we can't lock out GC so that + // has to be an acceptable risk. + if (!ch->is_valid_method(method)) { + trace->num_frames = -2; + return; + } + + if (DebugNonSafepoints_IS_CLEARED) { + // Take whatever method the top-frame decoder managed to scrape up. + // We look further at the top frame only if non-safepoint + // debugging information is available. + count++; + trace->num_frames = count; + trace->frames[0].method_id = method->find_jmethod_id_or_null(); + if (!method->is_native()) { + trace->frames[0].lineno = bci; + } else { + trace->frames[0].lineno = -3; + } + } + } + + // check has_last_Java_frame() after looking at the top frame + // which may be an interpreted Java frame. + if (!thd->has_last_Java_frame() && method == NULL) { + trace->num_frames = 0; + return; + } + + vframeStreamForte st(thd, walkframe, false); + for (; !st.at_end() && count < depth; st.forte_next(), count++) { + bci = st.bci(); + method = st.method(); + + // The method is not stored GC safe so see if GC became active + // after we entered AsyncGetCallTrace() and before we try to + // use the methodOop. + // Yes, there is still a window after this check and before + // we use methodOop below, but we can't lock out GC so that + // has to be an acceptable risk. + if (!ch->is_valid_method(method)) { + // we throw away everything we've gathered in this sample since + // none of it is safe + trace->num_frames = -2; + return; + } + + trace->frames[count].method_id = method->find_jmethod_id_or_null(); + if (!method->is_native()) { + trace->frames[count].lineno = bci; + } else { + trace->frames[count].lineno = -3; + } + } + trace->num_frames = count; + return; +} + + +// Forte Analyzer AsyncGetCallTrace() entry point. Currently supported +// on Linux X86, Solaris SPARC and Solaris X86. +// +// Async-safe version of GetCallTrace being called from a signal handler +// when a LWP gets interrupted by SIGPROF but the stack traces are filled +// with different content (see below). +// +// This function must only be called when JVM/TI +// CLASS_LOAD events have been enabled since agent startup. The enabled +// event will cause the jmethodIDs to be allocated at class load time. +// The jmethodIDs cannot be allocated in a signal handler because locks +// cannot be grabbed in a signal handler safely. +// +// void (*AsyncGetCallTrace)(ASGCT_CallTrace *trace, jint depth, void* ucontext) +// +// Called by the profiler to obtain the current method call stack trace for +// a given thread. The thread is identified by the env_id field in the +// ASGCT_CallTrace structure. The profiler agent should allocate a ASGCT_CallTrace +// structure with enough memory for the requested stack depth. The VM fills in +// the frames buffer and the num_frames field. +// +// Arguments: +// +// trace - trace data structure to be filled by the VM. +// depth - depth of the call stack trace. +// ucontext - ucontext_t of the LWP +// +// ASGCT_CallTrace: +// typedef struct { +// JNIEnv *env_id; +// jint num_frames; +// ASGCT_CallFrame *frames; +// } ASGCT_CallTrace; +// +// Fields: +// env_id - ID of thread which executed this trace. +// num_frames - number of frames in the trace. +// (< 0 indicates the frame is not walkable). +// frames - the ASGCT_CallFrames that make up this trace. Callee followed by callers. +// +// ASGCT_CallFrame: +// typedef struct { +// jint lineno; +// jmethodID method_id; +// } ASGCT_CallFrame; +// +// Fields: +// 1) For Java frame (interpreted and compiled), +// lineno - bci of the method being executed or -1 if bci is not available +// method_id - jmethodID of the method being executed +// 2) For native method +// lineno - (-3) +// method_id - jmethodID of the method being executed + +extern "C" { +void AsyncGetCallTrace(ASGCT_CallTrace *trace, jint depth, void* ucontext) { + if (SafepointSynchronize::is_synchronizing()) { + // The safepoint mechanism is trying to synchronize all the threads. + // Since this can involve thread suspension, it is not safe for us + // to be here. We can reduce the deadlock risk window by quickly + // returning to the SIGPROF handler. However, it is still possible + // for VMThread to catch us here or in the SIGPROF handler. If we + // are suspended while holding a resource and another thread blocks + // on that resource in the SIGPROF handler, then we will have a + // three-thread deadlock (VMThread, this thread, the other thread). + trace->num_frames = -10; + return; + } + + JavaThread* thread; + + if (trace->env_id == NULL || + (thread = JavaThread::thread_from_jni_environment(trace->env_id)) == NULL || + thread->is_exiting()) { + + // bad env_id, thread has exited or thread is exiting + trace->num_frames = -8; + return; + } + + if (thread->in_deopt_handler()) { + // thread is in the deoptimization handler so return no frames + trace->num_frames = -9; + return; + } + + assert(JavaThread::current() == thread, + "AsyncGetCallTrace must be called by the current interrupted thread"); + + if (!JvmtiExport::should_post_class_load()) { + trace->num_frames = -1; + return; + } + + if (Universe::heap()->is_gc_active()) { + trace->num_frames = -2; + return; + } + + switch (thread->thread_state()) { + case _thread_new: + case _thread_uninitialized: + case _thread_new_trans: + // We found the thread on the threads list above, but it is too + // young to be useful so return that there are no Java frames. + trace->num_frames = 0; + break; + case _thread_in_native: + case _thread_in_native_trans: + case _thread_blocked: + case _thread_blocked_trans: + case _thread_in_vm: + case _thread_in_vm_trans: + { + frame fr; + + // param isInJava == false - indicate we aren't in Java code + if (!thread->pd_get_top_frame_for_signal_handler(&fr, ucontext, false)) { + if (!thread->has_last_Java_frame()) { + trace->num_frames = 0; // no Java frames + } else { + trace->num_frames = -3; // unknown frame + } + } else { + trace->num_frames = -4; // non walkable frame by default + forte_fill_call_trace_given_top(thread, trace, depth, fr); + } + } + break; + case _thread_in_Java: + case _thread_in_Java_trans: + { + frame fr; + + // param isInJava == true - indicate we are in Java code + if (!thread->pd_get_top_frame_for_signal_handler(&fr, ucontext, true)) { + trace->num_frames = -5; // unknown frame + } else { + trace->num_frames = -6; // non walkable frame by default + forte_fill_call_trace_given_top(thread, trace, depth, fr); + } + } + break; + default: + // Unknown thread state + trace->num_frames = -7; + break; + } +} + + +#ifndef _WINDOWS +// Support for the Forte(TM) Peformance Tools collector. +// +// The method prototype is derived from libcollector.h. For more +// information, please see the libcollect man page. + +// Method to let libcollector know about a dynamically loaded function. +// Because it is weakly bound, the calls become NOP's when the library +// isn't present. +void collector_func_load(char* name, + void* null_argument_1, + void* null_argument_2, + void *vaddr, + int size, + int zero_argument, + void* null_argument_3); +#pragma weak collector_func_load +#define collector_func_load(x0,x1,x2,x3,x4,x5,x6) \ + ( collector_func_load ? collector_func_load(x0,x1,x2,x3,x4,x5,x6),0 : 0 ) +#endif // !_WINDOWS + +} // end extern "C" +#endif // !IA64 + +void Forte::register_stub(const char* name, address start, address end) { +#if !defined(_WINDOWS) && !defined(IA64) + assert(pointer_delta(end, start, sizeof(jbyte)) < INT_MAX, + "Code size exceeds maximum range") + + collector_func_load((char*)name, NULL, NULL, start, + pointer_delta(end, start, sizeof(jbyte)), 0, NULL); +#endif // !_WINDOWS && !IA64 +}