forte.cpp revision 2721:f08d439fab8c
154359Sroberto/* 254359Sroberto * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. 354359Sroberto * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 454359Sroberto * 554359Sroberto * This code is free software; you can redistribute it and/or modify it 654359Sroberto * under the terms of the GNU General Public License version 2 only, as 754359Sroberto * published by the Free Software Foundation. 854359Sroberto * 982498Sroberto * This code is distributed in the hope that it will be useful, but WITHOUT 1082498Sroberto * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1154359Sroberto * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1282498Sroberto * version 2 for more details (a copy is included in the LICENSE file that 13106163Sroberto * accompanied this code). 1482498Sroberto * 1582498Sroberto * You should have received a copy of the GNU General Public License version 1682498Sroberto * 2 along with this work; if not, write to the Free Software Foundation, 1782498Sroberto * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1882498Sroberto * 1982498Sroberto * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2082498Sroberto * or visit www.oracle.com if you need additional information or have any 2182498Sroberto * questions. 2282498Sroberto * 2382498Sroberto */ 24182007Sroberto 25182007Sroberto#include "precompiled.hpp" 26182007Sroberto#include "code/debugInfoRec.hpp" 27182007Sroberto#include "code/pcDesc.hpp" 28182007Sroberto#include "gc_interface/collectedHeap.inline.hpp" 29182007Sroberto#include "memory/space.hpp" 3054359Sroberto#include "memory/universe.inline.hpp" 3154359Sroberto#include "oops/oop.inline.hpp" 3254359Sroberto#include "oops/oop.inline2.hpp" 3354359Sroberto#include "prims/forte.hpp" 3454359Sroberto#include "runtime/thread.hpp" 3554359Sroberto#include "runtime/vframe.hpp" 3654359Sroberto#include "runtime/vframeArray.hpp" 3754359Sroberto 3882498Sroberto// These name match the names reported by the forte quality kit 3954359Srobertoenum { 4054359Sroberto ticks_no_Java_frame = 0, 41106163Sroberto ticks_no_class_load = -1, 42106163Sroberto ticks_GC_active = -2, 43106163Sroberto ticks_unknown_not_Java = -3, 44106163Sroberto ticks_not_walkable_not_Java = -4, 45106163Sroberto ticks_unknown_Java = -5, 4682498Sroberto ticks_not_walkable_Java = -6, 4782498Sroberto ticks_unknown_state = -7, 4882498Sroberto ticks_thread_exit = -8, 4954359Sroberto ticks_deopt = -9, 5054359Sroberto ticks_safepoint = -10 5154359Sroberto}; 5254359Sroberto 5354359Sroberto//------------------------------------------------------- 54132451Sroberto 55132451Sroberto// Native interfaces for use by Forte tools. 5654359Sroberto 5754359Sroberto 5854359Sroberto#ifndef IA64 5954359Sroberto 6054359Srobertoclass vframeStreamForte : public vframeStreamCommon { 6154359Sroberto public: 6254359Sroberto // constructor that starts with sender of frame fr (top_frame) 63182007Sroberto vframeStreamForte(JavaThread *jt, frame fr, bool stop_at_java_call_stub); 64182007Sroberto void forte_next(); 65182007Sroberto}; 66182007Sroberto 67182007Sroberto 68182007Srobertostatic bool is_decipherable_compiled_frame(JavaThread* thread, frame* fr, nmethod* nm); 6954359Srobertostatic bool is_decipherable_interpreted_frame(JavaThread* thread, 7054359Sroberto frame* fr, 7154359Sroberto methodOop* method_p, 7254359Sroberto int* bci_p); 73132451Sroberto 74132451Sroberto 75132451Sroberto 76132451Sroberto 7754359SrobertovframeStreamForte::vframeStreamForte(JavaThread *jt, 7854359Sroberto frame fr, 7954359Sroberto bool stop_at_java_call_stub) : vframeStreamCommon(jt) { 80132451Sroberto 81182007Sroberto _stop_at_java_call_stub = stop_at_java_call_stub; 82182007Sroberto _frame = fr; 83132451Sroberto 8454359Sroberto // We must always have a valid frame to start filling 8554359Sroberto 86182007Sroberto bool filled_in = fill_from_frame(); 87182007Sroberto 8854359Sroberto assert(filled_in, "invariant"); 8954359Sroberto 9054359Sroberto} 9154359Sroberto 9254359Sroberto 9354359Sroberto// Solaris SPARC Compiler1 needs an additional check on the grandparent 9454359Sroberto// of the top_frame when the parent of the top_frame is interpreted and 9554359Sroberto// the grandparent is compiled. However, in this method we do not know 9654359Sroberto// the relationship of the current _frame relative to the top_frame so 9754359Sroberto// we implement a more broad sanity check. When the previous callee is 9854359Sroberto// interpreted and the current sender is compiled, we verify that the 9954359Sroberto// current sender is also walkable. If it is not walkable, then we mark 10054359Sroberto// the current vframeStream as at the end. 10154359Srobertovoid vframeStreamForte::forte_next() { 10254359Sroberto // handle frames with inlining 10354359Sroberto if (_mode == compiled_mode && 10454359Sroberto vframeStreamCommon::fill_in_compiled_inlined_sender()) { 10554359Sroberto return; 10654359Sroberto } 10754359Sroberto 108182007Sroberto // handle general case 10954359Sroberto 11054359Sroberto int loop_count = 0; 11154359Sroberto int loop_max = MaxJavaStackTraceDepth * 2; 112182007Sroberto 11354359Sroberto 11454359Sroberto do { 11554359Sroberto 116182007Sroberto loop_count++; 117182007Sroberto 118182007Sroberto // By the time we get here we should never see unsafe but better 119182007Sroberto // safe then segv'd 120182007Sroberto 12154359Sroberto if (loop_count > loop_max || !_frame.safe_for_sender(_thread)) { 12254359Sroberto _mode = at_end_mode; 12354359Sroberto return; 12454359Sroberto } 12554359Sroberto 12654359Sroberto _frame = _frame.sender(&_reg_map); 12754359Sroberto 128132451Sroberto } while (!fill_from_frame()); 129132451Sroberto} 130182007Sroberto 131182007Sroberto// Determine if 'fr' is a decipherable compiled frame. We are already 132132451Sroberto// assured that fr is for a java nmethod. 13354359Sroberto 134132451Srobertostatic bool is_decipherable_compiled_frame(JavaThread* thread, frame* fr, nmethod* nm) { 13554359Sroberto assert(nm->is_java_method(), "invariant"); 13654359Sroberto 137182007Sroberto if (thread->has_last_Java_frame() && thread->last_Java_pc() == fr->pc()) { 13854359Sroberto // We're stopped at a call into the JVM so look for a PcDesc with 139132451Sroberto // the actual pc reported by the frame. 14054359Sroberto PcDesc* pc_desc = nm->pc_desc_at(fr->pc()); 14154359Sroberto 14254359Sroberto // Did we find a useful PcDesc? 14354359Sroberto if (pc_desc != NULL && 14454359Sroberto pc_desc->scope_decode_offset() != DebugInformationRecorder::serialized_null) { 14554359Sroberto return true; 14654359Sroberto } 14754359Sroberto } 14854359Sroberto 14954359Sroberto // We're at some random pc in the nmethod so search for the PcDesc 15054359Sroberto // whose pc is greater than the current PC. It's done this way 15154359Sroberto // because the extra PcDescs that are recorded for improved debug 15254359Sroberto // info record the end of the region covered by the ScopeDesc 15354359Sroberto // instead of the beginning. 15454359Sroberto PcDesc* pc_desc = nm->pc_desc_near(fr->pc() + 1); 15554359Sroberto 15654359Sroberto // Now do we have a useful PcDesc? 15754359Sroberto if (pc_desc == NULL || 158182007Sroberto pc_desc->scope_decode_offset() == DebugInformationRecorder::serialized_null) { 15954359Sroberto // No debug information available for this pc 16054359Sroberto // vframeStream would explode if we try and walk the frames. 16154359Sroberto return false; 16254359Sroberto } 16354359Sroberto 16454359Sroberto // This PcDesc is useful however we must adjust the frame's pc 16554359Sroberto // so that the vframeStream lookups will use this same pc 16654359Sroberto fr->set_pc(pc_desc->real_pc(nm)); 16754359Sroberto return true; 16854359Sroberto} 16954359Sroberto 17054359Sroberto 17154359Sroberto// Determine if 'fr' is a walkable interpreted frame. Returns false 17256746Sroberto// if it is not. *method_p, and *bci_p are not set when false is 17354359Sroberto// returned. *method_p is non-NULL if frame was executing a Java 17454359Sroberto// method. *bci_p is != -1 if a valid BCI in the Java method could 17554359Sroberto// be found. 17654359Sroberto// Note: this method returns true when a valid Java method is found 17754359Sroberto// even if a valid BCI cannot be found. 17854359Sroberto 17954359Srobertostatic bool is_decipherable_interpreted_frame(JavaThread* thread, 18054359Sroberto frame* fr, 18154359Sroberto methodOop* method_p, 18254359Sroberto int* bci_p) { 18354359Sroberto assert(fr->is_interpreted_frame(), "just checking"); 18454359Sroberto 18554359Sroberto // top frame is an interpreted frame 18654359Sroberto // check if it is walkable (i.e. valid methodOop and valid bci) 18754359Sroberto 18854359Sroberto // Because we may be racing a gc thread the method and/or bci 18954359Sroberto // of a valid interpreter frame may look bad causing us to 19054359Sroberto // fail the is_interpreted_frame_valid test. If the thread 19154359Sroberto // is in any of the following states we are assured that the 19254359Sroberto // frame is in fact valid and we must have hit the race. 19354359Sroberto 19454359Sroberto JavaThreadState state = thread->thread_state(); 19554359Sroberto bool known_valid = (state == _thread_in_native || 19654359Sroberto state == _thread_in_vm || 19754359Sroberto state == _thread_blocked ); 19854359Sroberto 19954359Sroberto if (known_valid || fr->is_interpreted_frame_valid(thread)) { 20054359Sroberto 20154359Sroberto // The frame code should completely validate the frame so that 20254359Sroberto // references to methodOop and bci are completely safe to access 20354359Sroberto // If they aren't the frame code should be fixed not this 20454359Sroberto // code. However since gc isn't locked out the values could be 20554359Sroberto // stale. This is a race we can never completely win since we can't 20654359Sroberto // lock out gc so do one last check after retrieving their values 20754359Sroberto // from the frame for additional safety 20854359Sroberto 20954359Sroberto methodOop method = fr->interpreter_frame_method(); 21054359Sroberto 21154359Sroberto // We've at least found a method. 21254359Sroberto // NOTE: there is something to be said for the approach that 21354359Sroberto // if we don't find a valid bci then the method is not likely 214182007Sroberto // a valid method. Then again we may have caught an interpreter 215132451Sroberto // frame in the middle of construction and the bci field is 21654359Sroberto // not yet valid. 21754359Sroberto 21854359Sroberto *method_p = method; 21954359Sroberto 22054359Sroberto // See if gc may have invalidated method since we validated frame 22154359Sroberto 22254359Sroberto if (!Universe::heap()->is_valid_method(method)) return false; 223132451Sroberto 224182007Sroberto intptr_t bcx = fr->interpreter_frame_bcx(); 22554359Sroberto 22654359Sroberto int bci = method->validate_bci_from_bcx(bcx); 22754359Sroberto 22854359Sroberto // note: bci is set to -1 if not a valid bci 22954359Sroberto *bci_p = bci; 230132451Sroberto return true; 23154359Sroberto } 23254359Sroberto 23354359Sroberto return false; 23454359Sroberto} 23554359Sroberto 23654359Sroberto 23754359Sroberto// Determine if 'fr' can be used to find an initial Java frame. 23854359Sroberto// Return false if it can not find a fully decipherable Java frame 23954359Sroberto// (in other words a frame that isn't safe to use in a vframe stream). 24054359Sroberto// Obviously if it can't even find a Java frame false will also be returned. 241182007Sroberto// 24254359Sroberto// If we find a Java frame decipherable or not then by definition we have 24354359Sroberto// identified a method and that will be returned to the caller via method_p. 24454359Sroberto// If we can determine a bci that is returned also. (Hmm is it possible 24554359Sroberto// to return a method and bci and still return false? ) 24654359Sroberto// 24754359Sroberto// The initial Java frame we find (if any) is return via initial_frame_p. 24854359Sroberto// 24954359Sroberto 25054359Srobertostatic bool find_initial_Java_frame(JavaThread* thread, 25154359Sroberto frame* fr, 25254359Sroberto frame* initial_frame_p, 25354359Sroberto methodOop* method_p, 25454359Sroberto int* bci_p) { 25554359Sroberto 25654359Sroberto // It is possible that for a frame containing an nmethod 25754359Sroberto // we can capture the method but no bci. If we get no 25854359Sroberto // bci the frame isn't walkable but the method is usable. 25954359Sroberto // Therefore we init the returned methodOop to NULL so the 26054359Sroberto // caller can make the distinction. 26154359Sroberto 26254359Sroberto *method_p = NULL; 26354359Sroberto 26454359Sroberto // On the initial call to this method the frame we get may not be 26554359Sroberto // recognizable to us. This should only happen if we are in a JRT_LEAF 26654359Sroberto // or something called by a JRT_LEAF method. 26754359Sroberto 26854359Sroberto 26954359Sroberto 27054359Sroberto frame candidate = *fr; 27154359Sroberto 27254359Sroberto // If the starting frame we were given has no codeBlob associated with 273182007Sroberto // it see if we can find such a frame because only frames with codeBlobs 27454359Sroberto // are possible Java frames. 27554359Sroberto 27654359Sroberto if (fr->cb() == NULL) { 27754359Sroberto 27854359Sroberto // See if we can find a useful frame 27954359Sroberto int loop_count; 28054359Sroberto int loop_max = MaxJavaStackTraceDepth * 2; 28154359Sroberto RegisterMap map(thread, false); 28254359Sroberto 28354359Sroberto for (loop_count = 0; loop_count < loop_max; loop_count++) { 28454359Sroberto if (!candidate.safe_for_sender(thread)) return false; 28554359Sroberto candidate = candidate.sender(&map); 28654359Sroberto if (candidate.cb() != NULL) break; 28754359Sroberto } 28854359Sroberto if (candidate.cb() == NULL) return false; 28954359Sroberto } 29054359Sroberto 29154359Sroberto // We have a frame known to be in the codeCache 29254359Sroberto // We will hopefully be able to figure out something to do with it. 29354359Sroberto int loop_count; 29454359Sroberto int loop_max = MaxJavaStackTraceDepth * 2; 29554359Sroberto RegisterMap map(thread, false); 29654359Sroberto 29754359Sroberto for (loop_count = 0; loop_count < loop_max; loop_count++) { 29854359Sroberto 29954359Sroberto if (candidate.is_first_frame()) { 30054359Sroberto // If initial frame is frame from StubGenerator and there is no 30154359Sroberto // previous anchor, there are no java frames associated with a method 30254359Sroberto return false; 30354359Sroberto } 30454359Sroberto 30554359Sroberto if (candidate.is_interpreted_frame()) { 30654359Sroberto if (is_decipherable_interpreted_frame(thread, &candidate, method_p, bci_p)) { 30754359Sroberto *initial_frame_p = candidate; 30854359Sroberto return true; 30954359Sroberto } 31054359Sroberto 31154359Sroberto // Hopefully we got some data 31254359Sroberto return false; 31354359Sroberto } 31454359Sroberto 31554359Sroberto if (candidate.cb()->is_nmethod()) { 31654359Sroberto 31754359Sroberto nmethod* nm = (nmethod*) candidate.cb(); 31854359Sroberto *method_p = nm->method(); 31954359Sroberto 32054359Sroberto // If the frame isn't fully decipherable then the default 32154359Sroberto // value for the bci is a signal that we don't have a bci. 32254359Sroberto // If we have a decipherable frame this bci value will 32354359Sroberto // not be used. 32454359Sroberto 32554359Sroberto *bci_p = -1; 32654359Sroberto 327182007Sroberto *initial_frame_p = candidate; 32854359Sroberto 32954359Sroberto // Native wrapper code is trivial to decode by vframeStream 33054359Sroberto 33154359Sroberto if (nm->is_native_method()) return true; 332182007Sroberto 333132451Sroberto // If it isn't decipherable then we have found a pc that doesn't 33454359Sroberto // have a PCDesc that can get us a bci however we did find 33554359Sroberto // a method 33654359Sroberto 33754359Sroberto if (!is_decipherable_compiled_frame(thread, &candidate, nm)) { 33854359Sroberto return false; 33954359Sroberto } 34054359Sroberto 34154359Sroberto // is_decipherable_compiled_frame may modify candidate's pc 342132451Sroberto *initial_frame_p = candidate; 34354359Sroberto 34454359Sroberto assert(nm->pc_desc_at(candidate.pc()) != NULL, "if it's decipherable then pc must be valid"); 34554359Sroberto 34654359Sroberto return true; 34754359Sroberto } 34854359Sroberto 34954359Sroberto // Must be some stub frame that we don't care about 35054359Sroberto 35154359Sroberto if (!candidate.safe_for_sender(thread)) return false; 35254359Sroberto candidate = candidate.sender(&map); 35354359Sroberto 35454359Sroberto // If it isn't in the code cache something is wrong 35554359Sroberto // since once we find a frame in the code cache they 35654359Sroberto // all should be there. 35754359Sroberto 358182007Sroberto if (candidate.cb() == NULL) return false; 359182007Sroberto 360182007Sroberto } 361182007Sroberto 362182007Sroberto return false; 363182007Sroberto 36454359Sroberto} 36554359Sroberto 36654359Sroberto 36754359Sroberto// call frame copied from old .h file and renamed 36854359Srobertotypedef struct { 36954359Sroberto jint lineno; // line number in the source file 37054359Sroberto jmethodID method_id; // method executed in this frame 371182007Sroberto} ASGCT_CallFrame; 37254359Sroberto 37354359Sroberto// call trace copied from old .h file and renamed 374132451Srobertotypedef struct { 375132451Sroberto JNIEnv *env_id; // Env where trace was recorded 376132451Sroberto jint num_frames; // number of frames in this trace 377132451Sroberto ASGCT_CallFrame *frames; // frames 378132451Sroberto} ASGCT_CallTrace; 379132451Sroberto 38054359Srobertostatic void forte_fill_call_trace_given_top(JavaThread* thd, 38154359Sroberto ASGCT_CallTrace* trace, 38254359Sroberto int depth, 38354359Sroberto frame top_frame) { 38454359Sroberto NoHandleMark nhm; 38554359Sroberto 38654359Sroberto frame initial_Java_frame; 38754359Sroberto methodOop method; 38854359Sroberto int bci; 38954359Sroberto int count; 39054359Sroberto 39154359Sroberto count = 0; 39254359Sroberto assert(trace->frames != NULL, "trace->frames must be non-NULL"); 39354359Sroberto 39454359Sroberto bool fully_decipherable = find_initial_Java_frame(thd, &top_frame, &initial_Java_frame, &method, &bci); 39554359Sroberto 39654359Sroberto // The frame might not be walkable but still recovered a method 39754359Sroberto // (e.g. an nmethod with no scope info for the pc 39854359Sroberto 39954359Sroberto if (method == NULL) return; 40054359Sroberto 40154359Sroberto CollectedHeap* ch = Universe::heap(); 40254359Sroberto 40354359Sroberto // The method is not stored GC safe so see if GC became active 40454359Sroberto // after we entered AsyncGetCallTrace() and before we try to 40554359Sroberto // use the methodOop. 40654359Sroberto // Yes, there is still a window after this check and before 40754359Sroberto // we use methodOop below, but we can't lock out GC so that 40854359Sroberto // has to be an acceptable risk. 40954359Sroberto if (!ch->is_valid_method(method)) { 41054359Sroberto trace->num_frames = ticks_GC_active; // -2 41154359Sroberto return; 41254359Sroberto } 41354359Sroberto 41454359Sroberto // We got a Java frame however it isn't fully decipherable 41554359Sroberto // so it won't necessarily be safe to use it for the 41654359Sroberto // initial frame in the vframe stream. 41754359Sroberto 41854359Sroberto if (!fully_decipherable) { 41954359Sroberto // Take whatever method the top-frame decoder managed to scrape up. 42054359Sroberto // We look further at the top frame only if non-safepoint 42154359Sroberto // debugging information is available. 42254359Sroberto count++; 42354359Sroberto trace->num_frames = count; 42454359Sroberto trace->frames[0].method_id = method->find_jmethod_id_or_null(); 42554359Sroberto if (!method->is_native()) { 42654359Sroberto trace->frames[0].lineno = bci; 42754359Sroberto } else { 42854359Sroberto trace->frames[0].lineno = -3; 42954359Sroberto } 43054359Sroberto 43154359Sroberto if (!initial_Java_frame.safe_for_sender(thd)) return; 43254359Sroberto 43354359Sroberto RegisterMap map(thd, false); 43454359Sroberto initial_Java_frame = initial_Java_frame.sender(&map); 43554359Sroberto } 43654359Sroberto 43754359Sroberto vframeStreamForte st(thd, initial_Java_frame, false); 43854359Sroberto 43954359Sroberto for (; !st.at_end() && count < depth; st.forte_next(), count++) { 44054359Sroberto bci = st.bci(); 44154359Sroberto method = st.method(); 44254359Sroberto 44354359Sroberto // The method is not stored GC safe so see if GC became active 44454359Sroberto // after we entered AsyncGetCallTrace() and before we try to 44554359Sroberto // use the methodOop. 44654359Sroberto // Yes, there is still a window after this check and before 44754359Sroberto // we use methodOop below, but we can't lock out GC so that 44854359Sroberto // has to be an acceptable risk. 44954359Sroberto if (!ch->is_valid_method(method)) { 45054359Sroberto // we throw away everything we've gathered in this sample since 45154359Sroberto // none of it is safe 45254359Sroberto trace->num_frames = ticks_GC_active; // -2 45354359Sroberto return; 45454359Sroberto } 45554359Sroberto 45654359Sroberto trace->frames[count].method_id = method->find_jmethod_id_or_null(); 45754359Sroberto if (!method->is_native()) { 458182007Sroberto trace->frames[count].lineno = bci; 459132451Sroberto } else { 46054359Sroberto trace->frames[count].lineno = -3; 46154359Sroberto } 46254359Sroberto } 46354359Sroberto trace->num_frames = count; 46454359Sroberto return; 46554359Sroberto} 466182007Sroberto 467182007Sroberto 468182007Sroberto// Forte Analyzer AsyncGetCallTrace() entry point. Currently supported 469182007Sroberto// on Linux X86, Solaris SPARC and Solaris X86. 47054359Sroberto// 471182007Sroberto// Async-safe version of GetCallTrace being called from a signal handler 47254359Sroberto// when a LWP gets interrupted by SIGPROF but the stack traces are filled 47354359Sroberto// with different content (see below). 47454359Sroberto// 47554359Sroberto// This function must only be called when JVM/TI 47654359Sroberto// CLASS_LOAD events have been enabled since agent startup. The enabled 47754359Sroberto// event will cause the jmethodIDs to be allocated at class load time. 47854359Sroberto// The jmethodIDs cannot be allocated in a signal handler because locks 47954359Sroberto// cannot be grabbed in a signal handler safely. 48054359Sroberto// 48154359Sroberto// void (*AsyncGetCallTrace)(ASGCT_CallTrace *trace, jint depth, void* ucontext) 48254359Sroberto// 48354359Sroberto// Called by the profiler to obtain the current method call stack trace for 48454359Sroberto// a given thread. The thread is identified by the env_id field in the 48554359Sroberto// ASGCT_CallTrace structure. The profiler agent should allocate a ASGCT_CallTrace 48654359Sroberto// structure with enough memory for the requested stack depth. The VM fills in 48754359Sroberto// the frames buffer and the num_frames field. 48854359Sroberto// 48954359Sroberto// Arguments: 49054359Sroberto// 49154359Sroberto// trace - trace data structure to be filled by the VM. 49254359Sroberto// depth - depth of the call stack trace. 49354359Sroberto// ucontext - ucontext_t of the LWP 49454359Sroberto// 49554359Sroberto// ASGCT_CallTrace: 49654359Sroberto// typedef struct { 49754359Sroberto// JNIEnv *env_id; 49854359Sroberto// jint num_frames; 49954359Sroberto// ASGCT_CallFrame *frames; 50054359Sroberto// } ASGCT_CallTrace; 50154359Sroberto// 50254359Sroberto// Fields: 50354359Sroberto// env_id - ID of thread which executed this trace. 50454359Sroberto// num_frames - number of frames in the trace. 50582498Sroberto// (< 0 indicates the frame is not walkable). 50654359Sroberto// frames - the ASGCT_CallFrames that make up this trace. Callee followed by callers. 50754359Sroberto// 50854359Sroberto// ASGCT_CallFrame: 50954359Sroberto// typedef struct { 51054359Sroberto// jint lineno; 51154359Sroberto// jmethodID method_id; 51254359Sroberto// } ASGCT_CallFrame; 51354359Sroberto// 51454359Sroberto// Fields: 51554359Sroberto// 1) For Java frame (interpreted and compiled), 51654359Sroberto// lineno - bci of the method being executed or -1 if bci is not available 51754359Sroberto// method_id - jmethodID of the method being executed 51854359Sroberto// 2) For native method 51954359Sroberto// lineno - (-3) 52054359Sroberto// method_id - jmethodID of the method being executed 52154359Sroberto 52254359Srobertoextern "C" { 52354359SrobertoJNIEXPORT 52454359Srobertovoid AsyncGetCallTrace(ASGCT_CallTrace *trace, jint depth, void* ucontext) { 52554359Sroberto JavaThread* thread; 52654359Sroberto 52754359Sroberto if (trace->env_id == NULL || 52854359Sroberto (thread = JavaThread::thread_from_jni_environment(trace->env_id)) == NULL || 52954359Sroberto thread->is_exiting()) { 53054359Sroberto 53154359Sroberto // bad env_id, thread has exited or thread is exiting 53254359Sroberto trace->num_frames = ticks_thread_exit; // -8 53354359Sroberto return; 53454359Sroberto } 53554359Sroberto 53654359Sroberto if (thread->in_deopt_handler()) { 53754359Sroberto // thread is in the deoptimization handler so return no frames 53854359Sroberto trace->num_frames = ticks_deopt; // -9 53982498Sroberto return; 54054359Sroberto } 54154359Sroberto 54282498Sroberto assert(JavaThread::current() == thread, 54354359Sroberto "AsyncGetCallTrace must be called by the current interrupted thread"); 544182007Sroberto 545182007Sroberto if (!JvmtiExport::should_post_class_load()) { 54654359Sroberto trace->num_frames = ticks_no_class_load; // -1 54754359Sroberto return; 54854359Sroberto } 54954359Sroberto 55054359Sroberto if (Universe::heap()->is_gc_active()) { 55154359Sroberto trace->num_frames = ticks_GC_active; // -2 55254359Sroberto return; 55354359Sroberto } 55454359Sroberto 55554359Sroberto switch (thread->thread_state()) { 55654359Sroberto case _thread_new: 55754359Sroberto case _thread_uninitialized: 55854359Sroberto case _thread_new_trans: 55954359Sroberto // We found the thread on the threads list above, but it is too 56054359Sroberto // young to be useful so return that there are no Java frames. 56154359Sroberto trace->num_frames = 0; 56254359Sroberto break; 56354359Sroberto case _thread_in_native: 56454359Sroberto case _thread_in_native_trans: 56554359Sroberto case _thread_blocked: 56654359Sroberto case _thread_blocked_trans: 56754359Sroberto case _thread_in_vm: 56854359Sroberto case _thread_in_vm_trans: 56954359Sroberto { 57054359Sroberto frame fr; 571132451Sroberto 572132451Sroberto // param isInJava == false - indicate we aren't in Java code 57354359Sroberto if (!thread->pd_get_top_frame_for_signal_handler(&fr, ucontext, false)) { 57454359Sroberto trace->num_frames = ticks_unknown_not_Java; // -3 unknown frame 575132451Sroberto } else { 57654359Sroberto if (!thread->has_last_Java_frame()) { 57754359Sroberto trace->num_frames = 0; // No Java frames 578182007Sroberto } else { 579182007Sroberto trace->num_frames = ticks_not_walkable_not_Java; // -4 non walkable frame by default 58054359Sroberto forte_fill_call_trace_given_top(thread, trace, depth, fr); 58154359Sroberto 582182007Sroberto // This assert would seem to be valid but it is not. 58354359Sroberto // It would be valid if we weren't possibly racing a gc 58454359Sroberto // thread. A gc thread can make a valid interpreted frame 58554359Sroberto // look invalid. It's a small window but it does happen. 58654359Sroberto // The assert is left here commented out as a reminder. 58754359Sroberto // assert(trace->num_frames != ticks_not_walkable_not_Java, "should always be walkable"); 58854359Sroberto 589182007Sroberto } 59054359Sroberto } 591182007Sroberto } 59254359Sroberto break; 59354359Sroberto case _thread_in_Java: 59454359Sroberto case _thread_in_Java_trans: 59554359Sroberto { 596182007Sroberto frame fr; 597132451Sroberto 59854359Sroberto // param isInJava == true - indicate we are in Java code 599182007Sroberto if (!thread->pd_get_top_frame_for_signal_handler(&fr, ucontext, true)) { 60054359Sroberto trace->num_frames = ticks_unknown_Java; // -5 unknown frame 60154359Sroberto } else { 60254359Sroberto trace->num_frames = ticks_not_walkable_Java; // -6, non walkable frame by default 60354359Sroberto forte_fill_call_trace_given_top(thread, trace, depth, fr); 604182007Sroberto } 605182007Sroberto } 60654359Sroberto break; 607182007Sroberto default: 60854359Sroberto // Unknown thread state 609182007Sroberto trace->num_frames = ticks_unknown_state; // -7 61054359Sroberto break; 611132451Sroberto } 61254359Sroberto} 61354359Sroberto 61454359Sroberto 61554359Sroberto#ifndef _WINDOWS 61654359Sroberto// Support for the Forte(TM) Peformance Tools collector. 61754359Sroberto// 618182007Sroberto// The method prototype is derived from libcollector.h. For more 61954359Sroberto// information, please see the libcollect man page. 620132451Sroberto 62154359Sroberto// Method to let libcollector know about a dynamically loaded function. 62254359Sroberto// Because it is weakly bound, the calls become NOP's when the library 62354359Sroberto// isn't present. 62454359Sroberto#ifdef __APPLE__ 62554359Sroberto// XXXDARWIN: Link errors occur even when __attribute__((weak_import)) 62654359Sroberto// is added 62754359Sroberto#define collector_func_load(x0,x1,x2,x3,x4,x5,x6) (0) 62854359Sroberto#else 62954359Srobertovoid collector_func_load(char* name, 63054359Sroberto void* null_argument_1, 63154359Sroberto void* null_argument_2, 63254359Sroberto void *vaddr, 633182007Sroberto int size, 63454359Sroberto int zero_argument, 63554359Sroberto void* null_argument_3); 63654359Sroberto#pragma weak collector_func_load 63754359Sroberto#define collector_func_load(x0,x1,x2,x3,x4,x5,x6) \ 63854359Sroberto ( collector_func_load ? collector_func_load(x0,x1,x2,x3,x4,x5,x6),0 : 0 ) 63954359Sroberto#endif // __APPLE__ 640182007Sroberto#endif // !_WINDOWS 641182007Sroberto 642182007Sroberto} // end extern "C" 64354359Sroberto#endif // !IA64 64454359Sroberto 645182007Srobertovoid Forte::register_stub(const char* name, address start, address end) { 64654359Sroberto#if !defined(_WINDOWS) && !defined(IA64) 64754359Sroberto assert(pointer_delta(end, start, sizeof(jbyte)) < INT_MAX, 64854359Sroberto "Code size exceeds maximum range"); 64954359Sroberto 65054359Sroberto collector_func_load((char*)name, NULL, NULL, start, 65154359Sroberto pointer_delta(end, start, sizeof(jbyte)), 0, NULL); 65254359Sroberto#endif // !_WINDOWS && !IA64 65354359Sroberto} 65454359Sroberto