duke@435: /* coleenp@4037: * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * trims@1907: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA trims@1907: * or visit www.oracle.com if you need additional information or have any trims@1907: * questions. duke@435: * duke@435: */ duke@435: stefank@2314: #include "precompiled.hpp" stefank@2314: #include "code/debugInfoRec.hpp" stefank@2314: #include "code/pcDesc.hpp" stefank@2314: #include "gc_interface/collectedHeap.inline.hpp" stefank@2314: #include "memory/space.hpp" stefank@2314: #include "memory/universe.inline.hpp" stefank@2314: #include "oops/oop.inline.hpp" stefank@2314: #include "oops/oop.inline2.hpp" stefank@2314: #include "prims/forte.hpp" stefank@2314: #include "runtime/thread.hpp" stefank@2314: #include "runtime/vframe.hpp" stefank@2314: #include "runtime/vframeArray.hpp" duke@435: sgoldman@542: // These name match the names reported by the forte quality kit sgoldman@542: enum { sgoldman@542: ticks_no_Java_frame = 0, sgoldman@542: ticks_no_class_load = -1, sgoldman@542: ticks_GC_active = -2, sgoldman@542: ticks_unknown_not_Java = -3, sgoldman@542: ticks_not_walkable_not_Java = -4, sgoldman@542: ticks_unknown_Java = -5, sgoldman@542: ticks_not_walkable_Java = -6, sgoldman@542: ticks_unknown_state = -7, sgoldman@542: ticks_thread_exit = -8, sgoldman@542: ticks_deopt = -9, sgoldman@542: ticks_safepoint = -10 sgoldman@542: }; duke@435: duke@435: //------------------------------------------------------- duke@435: duke@435: // Native interfaces for use by Forte tools. duke@435: duke@435: duke@435: #ifndef IA64 duke@435: duke@435: class vframeStreamForte : public vframeStreamCommon { duke@435: public: duke@435: // constructor that starts with sender of frame fr (top_frame) duke@435: vframeStreamForte(JavaThread *jt, frame fr, bool stop_at_java_call_stub); duke@435: void forte_next(); duke@435: }; duke@435: duke@435: never@1784: static bool is_decipherable_compiled_frame(JavaThread* thread, frame* fr, nmethod* nm); sgoldman@542: static bool is_decipherable_interpreted_frame(JavaThread* thread, never@1784: frame* fr, coleenp@4037: Method** method_p, never@1784: int* bci_p); duke@435: duke@435: duke@435: duke@435: sgoldman@542: vframeStreamForte::vframeStreamForte(JavaThread *jt, sgoldman@542: frame fr, sgoldman@542: bool stop_at_java_call_stub) : vframeStreamCommon(jt) { duke@435: sgoldman@542: _stop_at_java_call_stub = stop_at_java_call_stub; sgoldman@542: _frame = fr; duke@435: sgoldman@542: // We must always have a valid frame to start filling duke@435: sgoldman@542: bool filled_in = fill_from_frame(); duke@435: sgoldman@542: assert(filled_in, "invariant"); duke@435: duke@435: } duke@435: duke@435: duke@435: // Solaris SPARC Compiler1 needs an additional check on the grandparent duke@435: // of the top_frame when the parent of the top_frame is interpreted and duke@435: // the grandparent is compiled. However, in this method we do not know duke@435: // the relationship of the current _frame relative to the top_frame so duke@435: // we implement a more broad sanity check. When the previous callee is duke@435: // interpreted and the current sender is compiled, we verify that the duke@435: // current sender is also walkable. If it is not walkable, then we mark duke@435: // the current vframeStream as at the end. duke@435: void vframeStreamForte::forte_next() { duke@435: // handle frames with inlining duke@435: if (_mode == compiled_mode && duke@435: vframeStreamCommon::fill_in_compiled_inlined_sender()) { duke@435: return; duke@435: } duke@435: duke@435: // handle general case duke@435: duke@435: int loop_count = 0; duke@435: int loop_max = MaxJavaStackTraceDepth * 2; duke@435: duke@435: duke@435: do { duke@435: sgoldman@542: loop_count++; duke@435: sgoldman@542: // By the time we get here we should never see unsafe but better sgoldman@542: // safe then segv'd duke@435: sgoldman@542: if (loop_count > loop_max || !_frame.safe_for_sender(_thread)) { duke@435: _mode = at_end_mode; duke@435: return; duke@435: } duke@435: sgoldman@542: _frame = _frame.sender(&_reg_map); duke@435: duke@435: } while (!fill_from_frame()); duke@435: } duke@435: sgoldman@542: // Determine if 'fr' is a decipherable compiled frame. We are already sgoldman@542: // assured that fr is for a java nmethod. duke@435: never@1784: static bool is_decipherable_compiled_frame(JavaThread* thread, frame* fr, nmethod* nm) { sgoldman@542: assert(nm->is_java_method(), "invariant"); duke@435: never@1784: if (thread->has_last_Java_frame() && thread->last_Java_pc() == fr->pc()) { never@1784: // We're stopped at a call into the JVM so look for a PcDesc with never@1784: // the actual pc reported by the frame. never@1784: PcDesc* pc_desc = nm->pc_desc_at(fr->pc()); sgoldman@542: never@1784: // Did we find a useful PcDesc? sgoldman@542: if (pc_desc != NULL && never@1784: pc_desc->scope_decode_offset() != DebugInformationRecorder::serialized_null) { never@1784: return true; duke@435: } duke@435: } sgoldman@542: never@1784: // We're at some random pc in the nmethod so search for the PcDesc never@1784: // whose pc is greater than the current PC. It's done this way never@1784: // because the extra PcDescs that are recorded for improved debug never@1784: // info record the end of the region covered by the ScopeDesc never@1784: // instead of the beginning. never@1784: PcDesc* pc_desc = nm->pc_desc_near(fr->pc() + 1); never@1784: never@1784: // Now do we have a useful PcDesc? never@1784: if (pc_desc == NULL || never@1784: pc_desc->scope_decode_offset() == DebugInformationRecorder::serialized_null) { never@1784: // No debug information available for this pc never@1784: // vframeStream would explode if we try and walk the frames. never@1784: return false; never@1784: } never@1784: never@1784: // This PcDesc is useful however we must adjust the frame's pc never@1784: // so that the vframeStream lookups will use this same pc never@1784: fr->set_pc(pc_desc->real_pc(nm)); sgoldman@542: return true; duke@435: } duke@435: never@1784: duke@435: // Determine if 'fr' is a walkable interpreted frame. Returns false duke@435: // if it is not. *method_p, and *bci_p are not set when false is duke@435: // returned. *method_p is non-NULL if frame was executing a Java duke@435: // method. *bci_p is != -1 if a valid BCI in the Java method could duke@435: // be found. duke@435: // Note: this method returns true when a valid Java method is found duke@435: // even if a valid BCI cannot be found. duke@435: sgoldman@542: static bool is_decipherable_interpreted_frame(JavaThread* thread, never@1784: frame* fr, coleenp@4037: Method** method_p, never@1784: int* bci_p) { duke@435: assert(fr->is_interpreted_frame(), "just checking"); duke@435: duke@435: // top frame is an interpreted frame coleenp@4037: // check if it is walkable (i.e. valid Method* and valid bci) sgoldman@542: sgoldman@542: // Because we may be racing a gc thread the method and/or bci sgoldman@542: // of a valid interpreter frame may look bad causing us to sgoldman@542: // fail the is_interpreted_frame_valid test. If the thread sgoldman@542: // is in any of the following states we are assured that the sgoldman@542: // frame is in fact valid and we must have hit the race. sgoldman@542: sgoldman@542: JavaThreadState state = thread->thread_state(); sgoldman@542: bool known_valid = (state == _thread_in_native || sgoldman@542: state == _thread_in_vm || sgoldman@542: state == _thread_blocked ); sgoldman@542: sgoldman@542: if (known_valid || fr->is_interpreted_frame_valid(thread)) { sgoldman@542: sgoldman@542: // The frame code should completely validate the frame so that coleenp@4037: // references to Method* and bci are completely safe to access sgoldman@542: // If they aren't the frame code should be fixed not this sgoldman@542: // code. However since gc isn't locked out the values could be sgoldman@542: // stale. This is a race we can never completely win since we can't sgoldman@542: // lock out gc so do one last check after retrieving their values sgoldman@542: // from the frame for additional safety sgoldman@542: coleenp@4037: Method* method = fr->interpreter_frame_method(); sgoldman@542: sgoldman@542: // We've at least found a method. sgoldman@542: // NOTE: there is something to be said for the approach that sgoldman@542: // if we don't find a valid bci then the method is not likely sgoldman@542: // a valid method. Then again we may have caught an interpreter sgoldman@542: // frame in the middle of construction and the bci field is sgoldman@542: // not yet valid. sgoldman@542: sgoldman@542: *method_p = method; coleenp@4295: if (!method->is_valid_method()) return false; sgoldman@542: sgoldman@542: intptr_t bcx = fr->interpreter_frame_bcx(); sgoldman@542: sgoldman@542: int bci = method->validate_bci_from_bcx(bcx); sgoldman@542: sgoldman@542: // note: bci is set to -1 if not a valid bci sgoldman@542: *bci_p = bci; sgoldman@542: return true; duke@435: } sgoldman@542: duke@435: return false; duke@435: } duke@435: duke@435: sgoldman@542: // Determine if 'fr' can be used to find an initial Java frame. sgoldman@542: // Return false if it can not find a fully decipherable Java frame sgoldman@542: // (in other words a frame that isn't safe to use in a vframe stream). sgoldman@542: // Obviously if it can't even find a Java frame false will also be returned. duke@435: // sgoldman@542: // If we find a Java frame decipherable or not then by definition we have sgoldman@542: // identified a method and that will be returned to the caller via method_p. sgoldman@542: // If we can determine a bci that is returned also. (Hmm is it possible sgoldman@542: // to return a method and bci and still return false? ) sgoldman@542: // sgoldman@542: // The initial Java frame we find (if any) is return via initial_frame_p. sgoldman@542: // duke@435: sgoldman@542: static bool find_initial_Java_frame(JavaThread* thread, sgoldman@542: frame* fr, sgoldman@542: frame* initial_frame_p, coleenp@4037: Method** method_p, sgoldman@542: int* bci_p) { sgoldman@542: sgoldman@542: // It is possible that for a frame containing an nmethod sgoldman@542: // we can capture the method but no bci. If we get no sgoldman@542: // bci the frame isn't walkable but the method is usable. coleenp@4037: // Therefore we init the returned Method* to NULL so the sgoldman@542: // caller can make the distinction. sgoldman@542: sgoldman@542: *method_p = NULL; sgoldman@542: sgoldman@542: // On the initial call to this method the frame we get may not be sgoldman@542: // recognizable to us. This should only happen if we are in a JRT_LEAF sgoldman@542: // or something called by a JRT_LEAF method. sgoldman@542: sgoldman@542: sgoldman@542: sgoldman@542: frame candidate = *fr; sgoldman@542: sgoldman@542: // If the starting frame we were given has no codeBlob associated with sgoldman@542: // it see if we can find such a frame because only frames with codeBlobs sgoldman@542: // are possible Java frames. sgoldman@542: sgoldman@542: if (fr->cb() == NULL) { sgoldman@542: sgoldman@542: // See if we can find a useful frame sgoldman@542: int loop_count; sgoldman@542: int loop_max = MaxJavaStackTraceDepth * 2; sgoldman@542: RegisterMap map(thread, false); sgoldman@542: sgoldman@542: for (loop_count = 0; loop_count < loop_max; loop_count++) { sgoldman@542: if (!candidate.safe_for_sender(thread)) return false; sgoldman@542: candidate = candidate.sender(&map); sgoldman@542: if (candidate.cb() != NULL) break; sgoldman@542: } sgoldman@542: if (candidate.cb() == NULL) return false; duke@435: } duke@435: sgoldman@542: // We have a frame known to be in the codeCache sgoldman@542: // We will hopefully be able to figure out something to do with it. sgoldman@542: int loop_count; sgoldman@542: int loop_max = MaxJavaStackTraceDepth * 2; sgoldman@542: RegisterMap map(thread, false); sgoldman@542: sgoldman@542: for (loop_count = 0; loop_count < loop_max; loop_count++) { sgoldman@542: sgoldman@542: if (candidate.is_first_frame()) { sgoldman@542: // If initial frame is frame from StubGenerator and there is no sgoldman@542: // previous anchor, there are no java frames associated with a method sgoldman@542: return false; sgoldman@542: } sgoldman@542: sgoldman@542: if (candidate.is_interpreted_frame()) { sgoldman@542: if (is_decipherable_interpreted_frame(thread, &candidate, method_p, bci_p)) { sgoldman@542: *initial_frame_p = candidate; sgoldman@542: return true; sgoldman@542: } sgoldman@542: sgoldman@542: // Hopefully we got some data sgoldman@542: return false; sgoldman@542: } sgoldman@542: sgoldman@542: if (candidate.cb()->is_nmethod()) { sgoldman@542: sgoldman@542: nmethod* nm = (nmethod*) candidate.cb(); sgoldman@542: *method_p = nm->method(); sgoldman@542: sgoldman@542: // If the frame isn't fully decipherable then the default sgoldman@542: // value for the bci is a signal that we don't have a bci. sgoldman@542: // If we have a decipherable frame this bci value will sgoldman@542: // not be used. sgoldman@542: sgoldman@542: *bci_p = -1; sgoldman@542: sgoldman@542: *initial_frame_p = candidate; sgoldman@542: sgoldman@542: // Native wrapper code is trivial to decode by vframeStream sgoldman@542: sgoldman@542: if (nm->is_native_method()) return true; sgoldman@542: sgoldman@542: // If it isn't decipherable then we have found a pc that doesn't sgoldman@542: // have a PCDesc that can get us a bci however we did find sgoldman@542: // a method sgoldman@542: never@1784: if (!is_decipherable_compiled_frame(thread, &candidate, nm)) { sgoldman@542: return false; sgoldman@542: } sgoldman@542: sgoldman@542: // is_decipherable_compiled_frame may modify candidate's pc sgoldman@542: *initial_frame_p = candidate; sgoldman@542: never@1784: assert(nm->pc_desc_at(candidate.pc()) != NULL, "if it's decipherable then pc must be valid"); never@1784: sgoldman@542: return true; sgoldman@542: } sgoldman@542: sgoldman@542: // Must be some stub frame that we don't care about sgoldman@542: sgoldman@542: if (!candidate.safe_for_sender(thread)) return false; sgoldman@542: candidate = candidate.sender(&map); sgoldman@542: sgoldman@542: // If it isn't in the code cache something is wrong sgoldman@542: // since once we find a frame in the code cache they sgoldman@542: // all should be there. sgoldman@542: sgoldman@542: if (candidate.cb() == NULL) return false; sgoldman@542: duke@435: } duke@435: sgoldman@542: return false; duke@435: duke@435: } duke@435: duke@435: duke@435: // call frame copied from old .h file and renamed duke@435: typedef struct { duke@435: jint lineno; // line number in the source file duke@435: jmethodID method_id; // method executed in this frame duke@435: } ASGCT_CallFrame; duke@435: duke@435: // call trace copied from old .h file and renamed duke@435: typedef struct { duke@435: JNIEnv *env_id; // Env where trace was recorded duke@435: jint num_frames; // number of frames in this trace duke@435: ASGCT_CallFrame *frames; // frames duke@435: } ASGCT_CallTrace; duke@435: duke@435: static void forte_fill_call_trace_given_top(JavaThread* thd, sgoldman@542: ASGCT_CallTrace* trace, sgoldman@542: int depth, sgoldman@542: frame top_frame) { duke@435: NoHandleMark nhm; duke@435: sgoldman@542: frame initial_Java_frame; coleenp@4037: Method* method; duke@435: int bci; duke@435: int count; duke@435: duke@435: count = 0; duke@435: assert(trace->frames != NULL, "trace->frames must be non-NULL"); duke@435: sgoldman@542: bool fully_decipherable = find_initial_Java_frame(thd, &top_frame, &initial_Java_frame, &method, &bci); sgoldman@542: sgoldman@542: // The frame might not be walkable but still recovered a method coleenp@4295: // (e.g. an nmethod with no scope info for the pc) sgoldman@542: sgoldman@542: if (method == NULL) return; sgoldman@542: coleenp@4295: if (!method->is_valid_method()) { sgoldman@542: trace->num_frames = ticks_GC_active; // -2 duke@435: return; duke@435: } duke@435: sgoldman@542: // We got a Java frame however it isn't fully decipherable sgoldman@542: // so it won't necessarily be safe to use it for the sgoldman@542: // initial frame in the vframe stream. duke@435: sgoldman@542: if (!fully_decipherable) { sgoldman@542: // Take whatever method the top-frame decoder managed to scrape up. sgoldman@542: // We look further at the top frame only if non-safepoint sgoldman@542: // debugging information is available. sgoldman@542: count++; sgoldman@542: trace->num_frames = count; sgoldman@542: trace->frames[0].method_id = method->find_jmethod_id_or_null(); sgoldman@542: if (!method->is_native()) { sgoldman@542: trace->frames[0].lineno = bci; sgoldman@542: } else { sgoldman@542: trace->frames[0].lineno = -3; duke@435: } duke@435: sgoldman@542: if (!initial_Java_frame.safe_for_sender(thd)) return; sgoldman@542: sgoldman@542: RegisterMap map(thd, false); sgoldman@542: initial_Java_frame = initial_Java_frame.sender(&map); duke@435: } duke@435: sgoldman@542: vframeStreamForte st(thd, initial_Java_frame, false); duke@435: duke@435: for (; !st.at_end() && count < depth; st.forte_next(), count++) { duke@435: bci = st.bci(); duke@435: method = st.method(); duke@435: coleenp@4295: if (!method->is_valid_method()) { duke@435: // we throw away everything we've gathered in this sample since duke@435: // none of it is safe sgoldman@542: trace->num_frames = ticks_GC_active; // -2 duke@435: return; duke@435: } duke@435: duke@435: trace->frames[count].method_id = method->find_jmethod_id_or_null(); duke@435: if (!method->is_native()) { duke@435: trace->frames[count].lineno = bci; duke@435: } else { duke@435: trace->frames[count].lineno = -3; duke@435: } duke@435: } duke@435: trace->num_frames = count; duke@435: return; duke@435: } duke@435: duke@435: duke@435: // Forte Analyzer AsyncGetCallTrace() entry point. Currently supported duke@435: // on Linux X86, Solaris SPARC and Solaris X86. duke@435: // duke@435: // Async-safe version of GetCallTrace being called from a signal handler duke@435: // when a LWP gets interrupted by SIGPROF but the stack traces are filled duke@435: // with different content (see below). duke@435: // duke@435: // This function must only be called when JVM/TI duke@435: // CLASS_LOAD events have been enabled since agent startup. The enabled duke@435: // event will cause the jmethodIDs to be allocated at class load time. duke@435: // The jmethodIDs cannot be allocated in a signal handler because locks duke@435: // cannot be grabbed in a signal handler safely. duke@435: // duke@435: // void (*AsyncGetCallTrace)(ASGCT_CallTrace *trace, jint depth, void* ucontext) duke@435: // duke@435: // Called by the profiler to obtain the current method call stack trace for duke@435: // a given thread. The thread is identified by the env_id field in the duke@435: // ASGCT_CallTrace structure. The profiler agent should allocate a ASGCT_CallTrace duke@435: // structure with enough memory for the requested stack depth. The VM fills in duke@435: // the frames buffer and the num_frames field. duke@435: // duke@435: // Arguments: duke@435: // duke@435: // trace - trace data structure to be filled by the VM. duke@435: // depth - depth of the call stack trace. duke@435: // ucontext - ucontext_t of the LWP duke@435: // duke@435: // ASGCT_CallTrace: duke@435: // typedef struct { duke@435: // JNIEnv *env_id; duke@435: // jint num_frames; duke@435: // ASGCT_CallFrame *frames; duke@435: // } ASGCT_CallTrace; duke@435: // duke@435: // Fields: duke@435: // env_id - ID of thread which executed this trace. duke@435: // num_frames - number of frames in the trace. duke@435: // (< 0 indicates the frame is not walkable). duke@435: // frames - the ASGCT_CallFrames that make up this trace. Callee followed by callers. duke@435: // duke@435: // ASGCT_CallFrame: duke@435: // typedef struct { duke@435: // jint lineno; duke@435: // jmethodID method_id; duke@435: // } ASGCT_CallFrame; duke@435: // duke@435: // Fields: duke@435: // 1) For Java frame (interpreted and compiled), duke@435: // lineno - bci of the method being executed or -1 if bci is not available duke@435: // method_id - jmethodID of the method being executed duke@435: // 2) For native method duke@435: // lineno - (-3) duke@435: // method_id - jmethodID of the method being executed duke@435: duke@435: extern "C" { coleenp@2507: JNIEXPORT duke@435: void AsyncGetCallTrace(ASGCT_CallTrace *trace, jint depth, void* ucontext) { duke@435: JavaThread* thread; duke@435: duke@435: if (trace->env_id == NULL || duke@435: (thread = JavaThread::thread_from_jni_environment(trace->env_id)) == NULL || duke@435: thread->is_exiting()) { duke@435: duke@435: // bad env_id, thread has exited or thread is exiting sgoldman@542: trace->num_frames = ticks_thread_exit; // -8 duke@435: return; duke@435: } duke@435: duke@435: if (thread->in_deopt_handler()) { duke@435: // thread is in the deoptimization handler so return no frames sgoldman@542: trace->num_frames = ticks_deopt; // -9 duke@435: return; duke@435: } duke@435: duke@435: assert(JavaThread::current() == thread, duke@435: "AsyncGetCallTrace must be called by the current interrupted thread"); duke@435: duke@435: if (!JvmtiExport::should_post_class_load()) { sgoldman@542: trace->num_frames = ticks_no_class_load; // -1 duke@435: return; duke@435: } duke@435: duke@435: if (Universe::heap()->is_gc_active()) { sgoldman@542: trace->num_frames = ticks_GC_active; // -2 duke@435: return; duke@435: } duke@435: duke@435: switch (thread->thread_state()) { duke@435: case _thread_new: duke@435: case _thread_uninitialized: duke@435: case _thread_new_trans: duke@435: // We found the thread on the threads list above, but it is too duke@435: // young to be useful so return that there are no Java frames. duke@435: trace->num_frames = 0; duke@435: break; duke@435: case _thread_in_native: duke@435: case _thread_in_native_trans: duke@435: case _thread_blocked: duke@435: case _thread_blocked_trans: duke@435: case _thread_in_vm: duke@435: case _thread_in_vm_trans: duke@435: { duke@435: frame fr; duke@435: duke@435: // param isInJava == false - indicate we aren't in Java code duke@435: if (!thread->pd_get_top_frame_for_signal_handler(&fr, ucontext, false)) { sgoldman@542: trace->num_frames = ticks_unknown_not_Java; // -3 unknown frame sgoldman@542: } else { duke@435: if (!thread->has_last_Java_frame()) { sgoldman@542: trace->num_frames = 0; // No Java frames duke@435: } else { sgoldman@542: trace->num_frames = ticks_not_walkable_not_Java; // -4 non walkable frame by default sgoldman@542: forte_fill_call_trace_given_top(thread, trace, depth, fr); sgoldman@542: sgoldman@542: // This assert would seem to be valid but it is not. sgoldman@542: // It would be valid if we weren't possibly racing a gc sgoldman@542: // thread. A gc thread can make a valid interpreted frame sgoldman@542: // look invalid. It's a small window but it does happen. sgoldman@542: // The assert is left here commented out as a reminder. sgoldman@542: // assert(trace->num_frames != ticks_not_walkable_not_Java, "should always be walkable"); sgoldman@542: duke@435: } duke@435: } duke@435: } duke@435: break; duke@435: case _thread_in_Java: duke@435: case _thread_in_Java_trans: duke@435: { duke@435: frame fr; duke@435: duke@435: // param isInJava == true - indicate we are in Java code duke@435: if (!thread->pd_get_top_frame_for_signal_handler(&fr, ucontext, true)) { sgoldman@542: trace->num_frames = ticks_unknown_Java; // -5 unknown frame duke@435: } else { sgoldman@542: trace->num_frames = ticks_not_walkable_Java; // -6, non walkable frame by default duke@435: forte_fill_call_trace_given_top(thread, trace, depth, fr); duke@435: } duke@435: } duke@435: break; duke@435: default: duke@435: // Unknown thread state sgoldman@542: trace->num_frames = ticks_unknown_state; // -7 duke@435: break; duke@435: } duke@435: } duke@435: duke@435: duke@435: #ifndef _WINDOWS duke@435: // Support for the Forte(TM) Peformance Tools collector. duke@435: // duke@435: // The method prototype is derived from libcollector.h. For more duke@435: // information, please see the libcollect man page. duke@435: duke@435: // Method to let libcollector know about a dynamically loaded function. duke@435: // Because it is weakly bound, the calls become NOP's when the library duke@435: // isn't present. never@3156: #ifdef __APPLE__ never@3156: // XXXDARWIN: Link errors occur even when __attribute__((weak_import)) never@3156: // is added never@3156: #define collector_func_load(x0,x1,x2,x3,x4,x5,x6) (0) never@3156: #else duke@435: void collector_func_load(char* name, duke@435: void* null_argument_1, duke@435: void* null_argument_2, duke@435: void *vaddr, duke@435: int size, duke@435: int zero_argument, duke@435: void* null_argument_3); duke@435: #pragma weak collector_func_load duke@435: #define collector_func_load(x0,x1,x2,x3,x4,x5,x6) \ duke@435: ( collector_func_load ? collector_func_load(x0,x1,x2,x3,x4,x5,x6),0 : 0 ) never@3156: #endif // __APPLE__ duke@435: #endif // !_WINDOWS duke@435: duke@435: } // end extern "C" duke@435: #endif // !IA64 duke@435: duke@435: void Forte::register_stub(const char* name, address start, address end) { duke@435: #if !defined(_WINDOWS) && !defined(IA64) duke@435: assert(pointer_delta(end, start, sizeof(jbyte)) < INT_MAX, jcoomes@1844: "Code size exceeds maximum range"); duke@435: duke@435: collector_func_load((char*)name, NULL, NULL, start, duke@435: pointer_delta(end, start, sizeof(jbyte)), 0, NULL); duke@435: #endif // !_WINDOWS && !IA64 duke@435: }