X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fstacktrace.c;h=461c09d18f68d38ff92196ac1ad0f2daf64febab;hb=8c81647e1c96715f45498a3ada7f795b5c9dfe81;hp=f7f3fb247c12fe1d03586ff68cec4f32d6186834;hpb=2f58bfc23f233234473d370da0be7219fb471165;p=cacao.git diff --git a/src/vm/jit/stacktrace.c b/src/vm/jit/stacktrace.c index f7f3fb247..461c09d18 100644 --- a/src/vm/jit/stacktrace.c +++ b/src/vm/jit/stacktrace.c @@ -1,9 +1,7 @@ -/* src/vm/jit/stacktrace.c - machine independet stacktrace system +/* src/vm/jit/stacktrace.c - machine independent stacktrace system - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien + Copyright (C) 1996-2005, 2006, 2007, 2008 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -22,201 +20,88 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Joseph Wenninger - - Changes: Christian Thalinger - Edwin Steiner - - $Id: stacktrace.c 4913 2006-05-14 14:02:51Z edwin $ - */ #include "config.h" #include +#include #include #include #include "vm/types.h" -#include "mm/boehm.h" +#include "md.h" + +#include "mm/gc-common.h" #include "mm/memory.h" -#include "native/native.h" + +#include "vm/jit/stacktrace.h" #include "vm/global.h" /* required here for native includes */ -#include "native/include/java_lang_ClassLoader.h" +#include "native/jni.h" +#include "native/llni.h" + +#include "native/include/java_lang_Object.h" #include "native/include/java_lang_Throwable.h" -#include "native/include/java_lang_VMThrowable.h" -#if defined(USE_THREADS) -# if defined(NATIVE_THREADS) -# include "threads/native/threads.h" -# else -# include "threads/green/threads.h" -# endif -#else -# include "threads/none/threads.h" +#if defined(WITH_CLASSPATH_GNU) +# include "native/include/gnu_classpath_Pointer.h" +# include "native/include/java_lang_VMThrowable.h" #endif +#include "threads/thread.h" + #include "toolbox/logging.h" + +#include "vm/array.h" #include "vm/builtin.h" -#include "vm/class.h" +#include "vm/cycles-stats.h" #include "vm/exceptions.h" -#include "vm/loader.h" -#include "vm/options.h" #include "vm/stringlocal.h" #include "vm/vm.h" + #include "vm/jit/asmpart.h" #include "vm/jit/codegen-common.h" +#include "vm/jit/linenumbertable.h" #include "vm/jit/methodheader.h" -#include "vm/cycles-stats.h" - - -/* linenumbertable_entry ******************************************************/ - -/* Keep the type of line the same as the pointer type, otherwise we - run into alignment troubles (like on MIPS64). */ +#include "vm/jit/methodtree.h" -typedef struct linenumbertable_entry linenumbertable_entry; +#include "vmcore/class.h" +#include "vmcore/loader.h" +#include "vmcore/method.h" +#include "vmcore/options.h" -struct linenumbertable_entry { - ptrint line; /* NOTE: see doc/inlining_stacktrace.txt for */ - u1 *pc; /* special meanings of line and pc. */ -}; /* global variables ***********************************************************/ -#if !defined(USE_THREADS) -stackframeinfo *_no_threads_stackframeinfo = NULL; -#endif - -CYCLES_STATS_DECLARE(stacktrace_overhead ,100,1) -CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace,40,5000) -CYCLES_STATS_DECLARE(stacktrace_getClassContext ,40,5000) -CYCLES_STATS_DECLARE(stacktrace_getCurrentClass ,40,5000) -CYCLES_STATS_DECLARE(stacktrace_getStack ,40,10000) +CYCLES_STATS_DECLARE(stacktrace_overhead , 100, 1) +CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace, 40, 5000) +CYCLES_STATS_DECLARE(stacktrace_get, 40, 5000) +CYCLES_STATS_DECLARE(stacktrace_getClassContext , 40, 5000) +CYCLES_STATS_DECLARE(stacktrace_getCurrentClass , 40, 5000) +CYCLES_STATS_DECLARE(stacktrace_get_stack , 40, 10000) -/* stacktrace_create_stackframeinfo ******************************************** +/* stacktrace_stackframeinfo_add *********************************************** - Creates an stackframe info structure for inline code in the - interpreter. + Fills a stackframe info structure with the given or calculated + values and adds it to the chain. *******************************************************************************/ -#if defined(ENABLE_INTRP) -void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv, u1 *sp, - u1 *ra) +void stacktrace_stackframeinfo_add(stackframeinfo_t *sfi, u1 *pv, u1 *sp, u1 *ra, u1 *xpc) { - stackframeinfo **psfi; - methodinfo *m; - - /* get current stackframe info pointer */ - - psfi = STACKFRAMEINFO; - - /* if we don't have pv handy */ - - if (pv == NULL) { -#if defined(ENABLE_INTRP) - if (opt_intrp) - pv = codegen_findmethod(ra); - else -#endif - { + stackframeinfo_t *currentsfi; + codeinfo *code; #if defined(ENABLE_JIT) - pv = md_codegen_findmethod(ra); + s4 framesize; #endif - } - } - - /* get methodinfo pointer from data segment */ - - m = *((methodinfo **) (pv + MethodPointer)); - - /* fill new stackframe info structure */ - - sfi->prev = *psfi; - sfi->method = m; - sfi->pv = pv; - sfi->sp = sp; - sfi->ra = ra; - - /* xpc is the same as ra, but is required in stacktrace_create */ - - sfi->xpc = ra; - - /* store new stackframe info pointer */ - - *psfi = sfi; -} -#endif /* defined(ENABLE_INTRP) */ + /* Get current stackframe info. */ -/* stacktrace_create_inline_stackframeinfo ************************************* - - Creates an stackframe info structure for an inline exception stub. - -*******************************************************************************/ - -void stacktrace_create_inline_stackframeinfo(stackframeinfo *sfi, u1 *pv, - u1 *sp, u1 *ra, u1 *xpc) -{ - stackframeinfo **psfi; - - /* get current stackframe info pointer */ - - psfi = STACKFRAMEINFO; - -#if defined(ENABLE_INTRP) - if (opt_intrp) { - /* if we don't have pv handy */ - - if (pv == NULL) - pv = codegen_findmethod(ra); - - } -#endif - - /* fill new stackframe info structure */ - - sfi->prev = *psfi; - sfi->method = NULL; - sfi->pv = pv; - sfi->sp = sp; - sfi->ra = ra; - sfi->xpc = xpc; - - /* store new stackframe info pointer */ - - *psfi = sfi; -} - - -/* stacktrace_create_extern_stackframeinfo ************************************* - - Creates an stackframe info structure for an extern exception - (hardware or assembler). - -*******************************************************************************/ - -void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv, - u1 *sp, u1 *ra, u1 *xpc) -{ - stackframeinfo **psfi; -#if !defined(__I386__) && !defined(__X86_64__) - bool isleafmethod; -#endif -#if defined(ENABLE_JIT) - s4 framesize; -#endif - - /* get current stackframe info pointer */ - - psfi = STACKFRAMEINFO; + currentsfi = threads_get_current_stackframeinfo(); /* sometimes we don't have pv handy (e.g. in asmpart.S: L_asm_call_jit_compiler_exception or in the interpreter). */ @@ -224,38 +109,51 @@ void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv, if (pv == NULL) { #if defined(ENABLE_INTRP) if (opt_intrp) - pv = codegen_findmethod(ra); + pv = methodtree_find(ra); else #endif { #if defined(ENABLE_JIT) - pv = md_codegen_findmethod(ra); +# if defined(__SPARC_64__) + pv = md_get_pv_from_stackframe(sp); +# else + pv = md_codegen_get_pv_from_pc(ra); +# endif #endif } } + /* Get codeinfo pointer for the parent Java method. */ + + code = code_get_codeinfo_for_pv(pv); + + /* XXX */ + /* assert(m != NULL); */ + #if defined(ENABLE_JIT) # if defined(ENABLE_INTRP) /* When using the interpreter, we pass RA to the function. */ if (!opt_intrp) { # endif -# if defined(__I386__) || defined(__X86_64__) +# if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__M68K__) /* On i386 and x86_64 we always have to get the return address from the stack. */ + /* m68k has return address on stack always */ + /* On S390 we use REG_RA as REG_ITMP3, so we have always to get + the RA from stack. */ framesize = *((u4 *) (pv + FrameSize)); ra = md_stacktrace_get_returnaddress(sp, framesize); # else - /* If the method is a non-leaf function, we need to get the return - address from the stack. For leaf functions the return address - is set correctly. This makes the assembler and the signal - handler code simpler. */ - - isleafmethod = *((s4 *) (pv + IsLeaf)); + /* If the method is a non-leaf function, we need to get the + return address from the stack. For leaf functions the + return address is set correctly. This makes the assembler + and the signal handler code simpler. The code is NULL is + the asm_vm_call_method special case. */ - if (!isleafmethod) { + if ((code == NULL) || !code_is_leafmethod(code)) { framesize = *((u4 *) (pv + FrameSize)); ra = md_stacktrace_get_returnaddress(sp, framesize); @@ -264,837 +162,638 @@ void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv, # if defined(ENABLE_INTRP) } # endif -#endif /* defined(ENABLE_JIT) */ - - /* fill new stackframe info structure */ - - sfi->prev = *psfi; - sfi->method = NULL; - sfi->pv = pv; - sfi->sp = sp; - sfi->ra = ra; - sfi->xpc = xpc; - - /* store new stackframe info pointer */ - - *psfi = sfi; -} - - -/* stacktrace_create_native_stackframeinfo ************************************* - - Creates a stackframe info structure for a native stub. - -*******************************************************************************/ - -void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv, - u1 *sp, u1 *ra) -{ - stackframeinfo **psfi; - methodinfo *m; - - /* get methodinfo pointer from data segment */ - - m = *((methodinfo **) (pv + MethodPointer)); - - /* get current stackframe info pointer */ - - psfi = STACKFRAMEINFO; - - /* fill new stackframe info structure */ - - sfi->prev = *psfi; - sfi->method = m; - sfi->pv = NULL; - sfi->sp = sp; - sfi->ra = ra; - sfi->xpc = NULL; - - /* store new stackframe info pointer */ - - *psfi = sfi; -} - - -/* stacktrace_remove_stackframeinfo ******************************************** +#endif - XXX + /* Calculate XPC when not given. The XPC is then the return + address of the current method minus 1 because the RA points to + the instruction after the call instruction. This is required + e.g. for method stubs. */ -*******************************************************************************/ + if (xpc == NULL) { + xpc = (void *) (((intptr_t) ra) - 1); + } -void stacktrace_remove_stackframeinfo(stackframeinfo *sfi) -{ - stackframeinfo **psfi; + /* Fill new stackframeinfo structure. */ + + sfi->prev = currentsfi; + sfi->code = code; + sfi->pv = pv; + sfi->sp = sp; + sfi->ra = ra; + sfi->xpc = xpc; + +#if !defined(NDEBUG) + if (opt_DebugStackFrameInfo) { + log_start(); + log_print("[stackframeinfo add : sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=", + sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc); + method_print(sfi->code->m); + log_print("]"); + log_finish(); + } +#endif - /* get current stackframe info pointer */ + /* Store new stackframeinfo pointer. */ - psfi = STACKFRAMEINFO; + threads_set_current_stackframeinfo(sfi); - /* restore the old pointer */ + /* set the native world flag for the current thread */ + /* ATTENTION: This flag tells the GC how to treat this thread in case of + a collection. Set this flag _after_ a valid stackframe info was set. */ - *psfi = sfi->prev; + THREAD_NATIVEWORLD_ENTER; } -/* stacktrace_inline_arithmeticexception *************************************** +/* stacktrace_stackframeinfo_remove ******************************************** - Creates an ArithemticException for inline stub. + Remove the given stackframeinfo from the chain in the current + thread. *******************************************************************************/ -java_objectheader *stacktrace_inline_arithmeticexception(u1 *pv, u1 *sp, - u1 *ra, u1 *xpc) +void stacktrace_stackframeinfo_remove(stackframeinfo_t *sfi) { - stackframeinfo sfi; - java_objectheader *o; - - /* create stackframeinfo */ - - stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc); - - /* create exception */ - - o = new_arithmeticexception(); - - /* remove stackframeinfo */ + /* Clear the native world flag for the current thread. */ + /* ATTENTION: Clear this flag _before_ removing the stackframe info. */ + + THREAD_NATIVEWORLD_EXIT; + +#if !defined(NDEBUG) + if (opt_DebugStackFrameInfo) { + log_start(); + log_print("[stackframeinfo remove: sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=", + sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc); + method_print(sfi->code->m); + log_print("]"); + log_finish(); + } +#endif - stacktrace_remove_stackframeinfo(&sfi); + /* Set previous stackframe info. */ - return o; + threads_set_current_stackframeinfo(sfi->prev); } -/* stacktrace_inline_arrayindexoutofboundsexception **************************** - - Creates an ArrayIndexOutOfBoundsException for inline stub. - -*******************************************************************************/ - -java_objectheader *stacktrace_inline_arrayindexoutofboundsexception(u1 *pv, - u1 *sp, - u1 *ra, - u1 *xpc, - s4 index) -{ - stackframeinfo sfi; - java_objectheader *o; - - /* create stackframeinfo */ - - stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc); - - /* create exception */ - - o = new_arrayindexoutofboundsexception(index); +/* stacktrace_stackframeinfo_fill ********************************************** - /* remove stackframeinfo */ + Fill the temporary stackframeinfo structure with the values given + in sfi. - stacktrace_remove_stackframeinfo(&sfi); - - return o; -} - - -/* stacktrace_inline_arraystoreexception *************************************** - - Creates an ArrayStoreException for inline stub. + IN: + tmpsfi ... temporary stackframeinfo + sfi ...... stackframeinfo to be used in the next iteration *******************************************************************************/ -java_objectheader *stacktrace_inline_arraystoreexception(u1 *pv, u1 *sp, u1 *ra, - u1 *xpc) +static inline void stacktrace_stackframeinfo_fill(stackframeinfo_t *tmpsfi, stackframeinfo_t *sfi) { - stackframeinfo sfi; - java_objectheader *o; - - /* create stackframeinfo */ + /* Sanity checks. */ - stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc); + assert(tmpsfi != NULL); + assert(sfi != NULL); - /* create exception */ + /* Fill the temporary stackframeinfo. */ - o = new_arraystoreexception(); + tmpsfi->code = sfi->code; + tmpsfi->pv = sfi->pv; + tmpsfi->sp = sfi->sp; + tmpsfi->ra = sfi->ra; + tmpsfi->xpc = sfi->xpc; - /* remove stackframeinfo */ + /* Set the previous stackframe info of the temporary one to the + next in the chain. */ - stacktrace_remove_stackframeinfo(&sfi); + tmpsfi->prev = sfi->prev; - return o; +#if !defined(NDEBUG) + if (opt_DebugStackTrace) + log_println("[stacktrace fill]"); +#endif } -/* stacktrace_inline_classcastexception **************************************** - - Creates an ClassCastException for inline stub. - -*******************************************************************************/ - -java_objectheader *stacktrace_inline_classcastexception(u1 *pv, u1 *sp, u1 *ra, - u1 *xpc) -{ - stackframeinfo sfi; - java_objectheader *o; - - /* create stackframeinfo */ +/* stacktrace_stackframeinfo_next ********************************************** - stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc); + Walk the stack (or the stackframeinfo-chain) to the next method and + return the new stackframe values in the temporary stackframeinfo + passed. - /* create exception */ + ATTENTION: This function does NOT skip builtin methods! - o = new_classcastexception(); - - /* remove stackframeinfo */ - - stacktrace_remove_stackframeinfo(&sfi); - - return o; -} - - -/* stacktrace_inline_nullpointerexception ************************************** - - Creates an NullPointerException for inline stub. + IN: + tmpsfi ... temporary stackframeinfo of current method *******************************************************************************/ -java_objectheader *stacktrace_inline_nullpointerexception(u1 *pv, u1 *sp, - u1 *ra, u1 *xpc) +static inline void stacktrace_stackframeinfo_next(stackframeinfo_t *tmpsfi) { - stackframeinfo sfi; - java_objectheader *o; - - /* create stackframeinfo */ + codeinfo *code; + void *pv; + void *sp; + void *ra; + void *xpc; + uint32_t framesize; + stackframeinfo_t *prevsfi; - stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc); + /* Sanity check. */ - /* create exception */ + assert(tmpsfi != NULL); - o = new_nullpointerexception(); + /* Get values from the stackframeinfo. */ - /* remove stackframeinfo */ + code = tmpsfi->code; + pv = tmpsfi->pv; + sp = tmpsfi->sp; + ra = tmpsfi->ra; + xpc = tmpsfi->xpc; + + /* Get the current stack frame size. */ - stacktrace_remove_stackframeinfo(&sfi); - - return o; -} + framesize = *((uint32_t *) (((intptr_t) pv) + FrameSize)); + /* Get the RA of the current stack frame (RA to the parent Java + method) if the current method is a non-leaf method. Otherwise + the value in the stackframeinfo is correct (from the signal + handler). */ -/* stacktrace_inline_fillInStackTrace ****************************************** - - Fills in the correct stacktrace into an existing exception object - (this one is for inline exception stubs). - -*******************************************************************************/ - -java_objectheader *stacktrace_inline_fillInStackTrace(u1 *pv, u1 *sp, u1 *ra, - u1 *xpc) -{ - stackframeinfo sfi; - java_objectheader *o; - methodinfo *m; +#if defined(ENABLE_JIT) +# if defined(ENABLE_INTRP) + if (opt_intrp) + ra = intrp_md_stacktrace_get_returnaddress(sp, framesize); + else +# endif + { + if (!code_is_leafmethod(code)) + ra = md_stacktrace_get_returnaddress(sp, framesize); + } +#else + ra = intrp_md_stacktrace_get_returnaddress(sp, framesize); +#endif - /* create stackframeinfo */ + /* Get the PV for the parent Java method. */ - stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc); +#if defined(ENABLE_INTRP) + if (opt_intrp) + pv = methodtree_find(ra); + else +#endif + { +#if defined(ENABLE_JIT) +# if defined(__SPARC_64__) + sp = md_get_framepointer(sp); + pv = md_get_pv_from_stackframe(sp); +# else + pv = md_codegen_get_pv_from_pc(ra); +# endif +#endif + } - /* get exception */ + /* Get the codeinfo pointer for the parent Java method. */ - o = *exceptionptr; - assert(o); + code = code_get_codeinfo_for_pv(pv); - /* clear exception */ + /* Calculate the SP for the parent Java method. */ - *exceptionptr = NULL; +#if defined(ENABLE_INTRP) + if (opt_intrp) + sp = *(u1 **) (sp - framesize); + else +#endif + { +#if defined(__I386__) || defined (__X86_64__) || defined (__M68K__) + sp = (void *) (((intptr_t) sp) + framesize + SIZEOF_VOID_P); +#elif defined(__SPARC_64__) + /* already has the new sp */ +#else + sp = (void *) (((intptr_t) sp) + framesize); +#endif + } - /* resolve methodinfo pointer from exception object */ + /* If the new codeinfo pointer is NULL we reached a + asm_vm_call_method function. In this case we get the next + values from the previous stackframeinfo in the chain. + Otherwise the new values have been calculated before. */ - m = class_resolvemethod(o->vftbl->class, - utf_fillInStackTrace, - utf_void__java_lang_Throwable); + if (code == NULL) { + prevsfi = tmpsfi->prev; - /* call function */ + /* If the previous stackframeinfo in the chain is NULL we + reached the top of the stacktrace. We set code and prev to + NULL to mark the end, which is checked in + stacktrace_stackframeinfo_end_check. */ - (void) vm_call_method(m, o); + if (prevsfi == NULL) { + tmpsfi->code = NULL; + tmpsfi->prev = NULL; + return; + } - /* remove stackframeinfo */ + /* Fill the temporary stackframeinfo with the new values. */ - stacktrace_remove_stackframeinfo(&sfi); + stacktrace_stackframeinfo_fill(tmpsfi, prevsfi); + } + else { + /* Store the new values in the stackframeinfo. NOTE: We + subtract 1 from the RA to get the XPC, because the RA + points to the instruction after the call instruction. */ + + tmpsfi->code = code; + tmpsfi->pv = pv; + tmpsfi->sp = sp; + tmpsfi->ra = ra; + tmpsfi->xpc = (void *) (((intptr_t) ra) - 1); + } - return o; +#if !defined(NDEBUG) + /* Print current method information. */ + + if (opt_DebugStackTrace) { + log_start(); + log_print("[stacktrace: method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=", + tmpsfi->code->m, tmpsfi->pv, tmpsfi->sp, tmpsfi->ra, + tmpsfi->xpc); + method_print(tmpsfi->code->m); + log_print("]"); + log_finish(); + } +#endif } -/* stacktrace_hardware_arithmeticexception ************************************* - - Creates an ArithemticException for inline stub. - -*******************************************************************************/ - -java_objectheader *stacktrace_hardware_arithmeticexception(u1 *pv, u1 *sp, - u1 *ra, u1 *xpc) -{ - stackframeinfo sfi; - java_objectheader *o; - - /* create stackframeinfo */ - - stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc); - - /* create exception */ - - o = new_arithmeticexception(); - - /* remove stackframeinfo */ - - stacktrace_remove_stackframeinfo(&sfi); - - return o; -} +/* stacktrace_stackframeinfo_end_check ***************************************** + Check if we reached the end of the stacktrace. -/* stacktrace_hardware_nullpointerexception ************************************ + IN: + tmpsfi ... temporary stackframeinfo of current method - Creates an NullPointerException for the SIGSEGV signal handler. + RETURN: + true .... the end is reached + false ... the end is not reached *******************************************************************************/ -java_objectheader *stacktrace_hardware_nullpointerexception(u1 *pv, u1 *sp, - u1 *ra, u1 *xpc) +static inline bool stacktrace_stackframeinfo_end_check(stackframeinfo_t *tmpsfi) { - stackframeinfo sfi; - java_objectheader *o; - - /* create stackframeinfo */ + /* Sanity check. */ - stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc); + assert(tmpsfi != NULL); - /* create exception */ + if ((tmpsfi->code == NULL) && (tmpsfi->prev == NULL)) { +#if !defined(NDEBUG) + if (opt_DebugStackTrace) + log_println("[stacktrace stop]"); +#endif - o = new_nullpointerexception(); + return true; + } - /* remove stackframeinfo */ + return false; +} - stacktrace_remove_stackframeinfo(&sfi); - return o; -} +/* stacktrace_depth ************************************************************ + Calculates and returns the depth of the current stacktrace. -/* stacktrace_add_entry ******************************************************** + IN: + sfi ... stackframeinfo where to start the stacktrace - Adds a new entry to the stacktrace buffer. + RETURN: + depth of the stacktrace *******************************************************************************/ -static void stacktrace_add_entry(stacktracebuffer *stb, methodinfo *m, u2 line) +static int stacktrace_depth(stackframeinfo_t *sfi) { - stacktrace_entry *ste; - - /* check if we already reached the buffer capacity */ - - if (stb->used >= stb->capacity) { - /* reallocate new memory */ - - stb->entries = DMREALLOC(stb->entries, stacktrace_entry, stb->capacity, - stb->capacity + STACKTRACE_CAPACITY_INCREMENT); - - /* set new buffer capacity */ - - stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT; - } - - /* insert the current entry */ + stackframeinfo_t tmpsfi; + int depth; + methodinfo *m; - ste = &(stb->entries[stb->used]); +#if !defined(NDEBUG) + if (opt_DebugStackTrace) + log_println("[stacktrace_depth]"); +#endif - ste->method = m; - ste->linenumber = line; + /* XXX This is not correct, but a workaround for threads-dump for + now. */ +/* assert(sfi != NULL); */ + if (sfi == NULL) + return 0; - /* increase entries used count */ + /* Iterate over all stackframes. */ - stb->used += 1; -} + depth = 0; + for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi); + stacktrace_stackframeinfo_end_check(&tmpsfi) == false; + stacktrace_stackframeinfo_next(&tmpsfi)) { + /* Get methodinfo. */ -/* stacktrace_add_method_intern ************************************************ + m = tmpsfi.code->m; - This function is used by stacktrace_add_method to search the line number - table for the line corresponding to a given pc. The function recurses for - inlined methods. + /* Skip builtin methods. */ -*******************************************************************************/ + if (m->flags & ACC_METHOD_BUILTIN) + continue; -static bool stacktrace_add_method_intern(stacktracebuffer *stb, - methodinfo *m, - linenumbertable_entry *lntentry, - ptrint lntsize, - u1 *pc) -{ - linenumbertable_entry *lntinline; /* special entry for inlined method */ - - assert(stb); - assert(lntentry); - - /* Find the line number for the specified PC (going backwards - in the linenumber table). The linenumber table size is zero - in native stubs. */ - - for (; lntsize > 0; lntsize--, lntentry--) { - - /* did we reach the current line? */ - - /* Note: In case of inlining this may actually compare the pc - against a methodinfo *, yielding a non-sensical - result. This is no problem, however, as we ignore such - entries in the switch below. This way we optimize for the - common case (ie. a real pc in lntentry->pc). */ - - if (pc >= lntentry->pc) { - - /* check for special inline entries (see - doc/inlining_stacktrace.txt for details */ - - if ((s4)lntentry->line < 0) { - switch (lntentry->line) { - case -1: - /* begin of inlined method (ie. INLINE_END - instruction) */ - - lntinline = --lntentry;/* get entry with methodinfo * */ - lntentry--; /* skip the special entry */ - lntsize -= 2; - - /* search inside the inlined method */ - if (stacktrace_add_method_intern( - stb, - (methodinfo*) lntinline->pc, - lntentry, - lntsize, - pc)) - { - /* the inlined method contained the pc */ - assert(lntinline->line <= -3); - stacktrace_add_entry(stb, m, (-3) - lntinline->line); - return true; - } - /* pc was not in inlined method, continue - search. Entries inside the inlined method - will be skipped because their lntentry->pc - is higher than pc. */ - break; - - case -2: - /* end of inlined method */ - return false; - - /* default: is only reached for an -3-line entry - after a skipped -2 entry. We can safely ignore - it and continue searching. */ - } - } - else { - /* found a normal entry */ - stacktrace_add_entry(stb, m, lntentry->line); - return true; - } - } + depth++; } - /* not found */ - return false; + return depth; } -/* stacktrace_add_method ******************************************************* - Add stacktrace entries[1] for the given method to the stacktrace buffer. +/* stacktrace_get ************************************************************** - IN: - stb.........stacktracebuffer to fill - m...........method for which entries should be created - pv..........pv of method - pc..........position of program counter within the method's code + Builds and returns a stacktrace starting from the given stackframe + info and returns the stacktrace structure wrapped in a Java + byte-array to not confuse the GC. - OUT: - true, if stacktrace entries were successfully created, false otherwise. + IN: + sfi ... stackframe info to start stacktrace from - [1] In case of inlined methods there may be more than one stacktrace - entry for a codegen-level method. (see doc/inlining_stacktrace.txt) + RETURN: + stacktrace as Java byte-array *******************************************************************************/ -static bool stacktrace_add_method(stacktracebuffer *stb, methodinfo *m, u1 *pv, - u1 *pc) +java_handle_bytearray_t *stacktrace_get(stackframeinfo_t *sfi) { - ptrint lntsize; /* size of line number table */ - u1 *lntstart; /* start of line number table */ - linenumbertable_entry *lntentry; /* points to last entry in the table */ - codeinfo *code; /* compiled realization of method */ - - /* get size of line number table */ - - lntsize = *((ptrint *) (pv + LineNumberTableSize)); - lntstart = *((u1 **) (pv + LineNumberTableStart)); - - /* Subtract the size of the line number entry of the structure, - since the line number table start points to the pc. */ + stackframeinfo_t tmpsfi; + int depth; + java_handle_bytearray_t *ba; + int32_t ba_size; + stacktrace_t *st; + stacktrace_entry_t *ste; + methodinfo *m; + bool skip_fillInStackTrace; + bool skip_init; - lntentry = (linenumbertable_entry *) (lntstart - SIZEOF_VOID_P); - - /* find the realization of the method the pc is in */ - /* XXX Note: This is preliminary. It would be cleaner */ - /* to get the codeinfo * from the PV */ + CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD - code = m->code; - while (1) { - if (!code) { -#ifndef NDEBUG - method_println(m); - dolog("Could not find codeinfo for Current PC: %p",(void*)pc); +#if !defined(NDEBUG) + if (opt_DebugStackTrace) + log_println("[stacktrace_get]"); #endif - abort(); - } - if (((ptrint)pc >= (ptrint)code->entrypoint) - && - ( (pc - (u1*)code->entrypoint) < code->mcodelength )) - { - /* found */ - break; - } + skip_fillInStackTrace = true; + skip_init = true; - code = code->prev; - } + depth = stacktrace_depth(sfi); - /* search the line number table */ + if (depth == 0) + return NULL; - if (stacktrace_add_method_intern(stb, m, lntentry, lntsize, pc)) - return true; + /* Allocate memory from the GC heap and copy the stacktrace + buffer. */ + /* ATTENTION: Use a Java byte-array for this to not confuse the + GC. */ + /* FIXME: We waste some memory here as we skip some entries + later. */ - /* If we get here, just add the entry with line number 0. */ + ba_size = sizeof(stacktrace_t) + sizeof(stacktrace_entry_t) * depth; - stacktrace_add_entry(stb, m, 0); + ba = builtin_newarray_byte(ba_size); - return true; -} + if (ba == NULL) + goto return_NULL; + /* Get a stacktrace entry pointer. */ + /* ATTENTION: We need a critical section here because we use the + byte-array data pointer directly. */ -/* stacktrace_create *********************************************************** + LLNI_CRITICAL_START; - Generates a stacktrace from the thread passed into a - stacktracebuffer. The stacktracebuffer is allocated on the GC - heap. + st = (stacktrace_t *) LLNI_array_data(ba); - RETURN VALUE: - pointer to the stacktracebuffer, or - NULL if an exception has been thrown + ste = st->entries; -*******************************************************************************/ + /* Iterate over the whole stack. */ -stacktracebuffer *stacktrace_create(threadobject* thread) -{ - stacktracebuffer *stb; - stackframeinfo *sfi; - methodinfo *m; - u1 *pv; - u1 *sp; - u4 framesize; - u1 *ra; - u1 *xpc; + for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi); + stacktrace_stackframeinfo_end_check(&tmpsfi) == false; + stacktrace_stackframeinfo_next(&tmpsfi)) { + /* Get the methodinfo. */ - /* prevent compiler warnings */ + m = tmpsfi.code->m; - pv = NULL; - sp = NULL; - ra = NULL; + /* Skip builtin methods. */ - /* create a stacktracebuffer in dump memory */ + if (m->flags & ACC_METHOD_BUILTIN) + continue; - stb = DNEW(stacktracebuffer); + /* This logic is taken from + hotspot/src/share/vm/classfile/javaClasses.cpp + (java_lang_Throwable::fill_in_stack_trace). */ - stb->capacity = STACKTRACE_CAPACITY_DEFAULT; - stb->used = 0; - stb->entries = DMNEW(stacktrace_entry, STACKTRACE_CAPACITY_DEFAULT); + if (skip_fillInStackTrace == true) { + /* Check "fillInStackTrace" only once, so we negate the + flag after the first time check. */ - /* The first element in the stackframe chain must always be a - native stackframeinfo (VMThrowable.fillInStackTrace is a native - function). */ +#if defined(WITH_CLASSPATH_GNU) + /* For GNU Classpath we also need to skip + VMThrowable.fillInStackTrace(). */ -#if defined(USE_THREADS) - sfi = thread->_stackframeinfo; -#else - sfi = _no_threads_stackframeinfo; + if ((m->clazz == class_java_lang_VMThrowable) && + (m->name == utf_fillInStackTrace)) + continue; #endif -#define PRINTMETHODS 0 + skip_fillInStackTrace = false; -#if PRINTMETHODS - printf("\n\nfillInStackTrace start:\n"); - fflush(stdout); -#endif + if (m->name == utf_fillInStackTrace) + continue; + } - /* Loop while we have a method pointer (asm_calljavafunction has - NULL) or there is a stackframeinfo in the chain. */ + /* Skip methods of the exceptions klass. If there is + methods that belongs to a superclass of the + exception we are going to skipping them in stack trace. */ - m = NULL; + if (skip_init == true) { + if ((m->name == utf_init) && + (class_issubclass(m->clazz, class_java_lang_Throwable))) { + continue; + } + else { + /* If no "Throwable.init()" method found, we stop + checking it next time. */ - while (m || sfi) { - /* m == NULL should only happen for the first time and inline - stackframe infos, like from the exception stubs or the - patcher wrapper. */ + skip_init = false; + } + } - if (m == NULL) { - /* for native stub stackframe infos, pv is always NULL */ + /* Store the stacktrace entry and increment the pointer. */ - if (sfi->pv == NULL) { - /* get methodinfo, sp and ra from the current stackframe info */ + ste->code = tmpsfi.code; + ste->pc = tmpsfi.xpc; - m = sfi->method; - sp = sfi->sp; /* sp of parent Java function */ - ra = sfi->ra; + ste++; + } - if (m) - stacktrace_add_entry(stb, m, 0); + /* Store the number of entries in the stacktrace structure. */ -#if PRINTMETHODS - printf("ra=%p sp=%p, ", ra, sp); - method_print(m); - printf(": native stub\n"); - fflush(stdout); -#endif - /* This is an native stub stackframe info, so we can - get the parent pv from the return address - (ICMD_INVOKE*). */ + st->length = ste - st->entries; -#if defined(ENABLE_INTRP) - if (opt_intrp) - pv = codegen_findmethod(ra); - else -#endif - { -#if defined(ENABLE_JIT) - pv = md_codegen_findmethod(ra); -#endif - } + LLNI_CRITICAL_END; - /* get methodinfo pointer from parent data segment */ + /* release dump memory */ - m = *((methodinfo **) (pv + MethodPointer)); +/* dump_release(dumpsize); */ - } else { - /* Inline stackframe infos are special: they have a - xpc of the actual exception position and the return - address saved since an inline stackframe info can - also be in a leaf method (no return address saved - on stack!!!). ATTENTION: This one is also for - hardware exceptions!!! */ + CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace, + stacktrace_overhead) + return ba; - /* get methodinfo, sp and ra from the current stackframe info */ +return_NULL: +/* dump_release(dumpsize); */ - m = sfi->method; /* m == NULL */ - pv = sfi->pv; /* pv of parent Java function */ - sp = sfi->sp; /* sp of parent Java function */ - ra = sfi->ra; /* ra of parent Java function */ - xpc = sfi->xpc; /* actual exception position */ + CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace, + stacktrace_overhead) -#if PRINTMETHODS - printf("ra=%p sp=%p, ", ra, sp); - printf("NULL: inline stub\n"); - fflush(stdout); -#endif + return NULL; +} - /* get methodinfo from current Java method */ - m = *((methodinfo **) (pv + MethodPointer)); +/* stacktrace_get_current ****************************************************** - /* if m == NULL, this is a asm_calljavafunction call */ + Builds and returns a stacktrace from the current thread and returns + the stacktrace structure wrapped in a Java byte-array to not + confuse the GC. - if (m != NULL) { -#if PRINTMETHODS - printf("ra=%p sp=%p, ", ra, sp); - method_print(m); - printf(": inline stub parent"); - fflush(stdout); -#endif + RETURN: + stacktrace as Java byte-array -#if defined(ENABLE_INTRP) - if (!opt_intrp) { -#endif +*******************************************************************************/ - /* add the method to the stacktrace */ +java_handle_bytearray_t *stacktrace_get_current(void) +{ + stackframeinfo_t *sfi; + java_handle_bytearray_t *ba; - stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) xpc)); + sfi = threads_get_current_stackframeinfo(); + ba = stacktrace_get(sfi); - /* get the current stack frame size */ + return ba; +} - framesize = *((u4 *) (pv + FrameSize)); -#if PRINTMETHODS - printf(", framesize=%d\n", framesize); - fflush(stdout); -#endif +/* stacktrace_get_caller_class ************************************************* - /* set stack pointer to stackframe of parent Java */ - /* function of the current Java function */ + Get the class on the stack at the given depth. This function skips + various special classes or methods. -#if defined(__I386__) || defined (__X86_64__) - sp += framesize + SIZEOF_VOID_P; -#else - sp += framesize; -#endif + ARGUMENTS: + depth ... depth to get caller class of - /* get data segment and methodinfo pointer from parent */ - /* method */ + RETURN: + caller class -#if defined(ENABLE_JIT) - pv = md_codegen_findmethod(ra); -#endif +*******************************************************************************/ - m = *((methodinfo **) (pv + MethodPointer)); +#if defined(ENABLE_JAVASE) +classinfo *stacktrace_get_caller_class(int depth) +{ + stackframeinfo_t *sfi; + stackframeinfo_t tmpsfi; + methodinfo *m; + classinfo *c; + int i; -#if defined(ENABLE_INTRP) - } -#endif - } -#if PRINTMETHODS - else { - printf("ra=%p sp=%p, ", ra, sp); - printf("asm_calljavafunction\n"); - fflush(stdout); - } +#if !defined(NDEBUG) + if (opt_DebugStackTrace) + log_println("[stacktrace_get_caller_class]"); #endif - } - /* get previous stackframeinfo in the chain */ + /* Get the stackframeinfo of the current thread. */ - sfi = sfi->prev; + sfi = threads_get_current_stackframeinfo(); - } else { -#if PRINTMETHODS - printf("ra=%p sp=%p, ", ra, sp); - method_print(m); - printf(": JIT"); - fflush(stdout); -#endif + /* Iterate over the whole stack until we reached the requested + depth. */ - /* JIT method found, add it to the stacktrace (we subtract - 1 from the return address since it points the the - instruction after call). */ + i = 0; - stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1); + for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi); + stacktrace_stackframeinfo_end_check(&tmpsfi) == false; + stacktrace_stackframeinfo_next(&tmpsfi)) { - /* get the current stack frame size */ + m = tmpsfi.code->m; + c = m->clazz; - framesize = *((u4 *) (pv + FrameSize)); + /* Skip builtin methods. */ -#if PRINTMETHODS - printf(", framesize=%d\n", framesize); - fflush(stdout); -#endif + if (m->flags & ACC_METHOD_BUILTIN) + continue; - /* get return address of current stack frame */ +#if defined(WITH_CLASSPATH_SUN) + /* NOTE: See hotspot/src/share/vm/runtime/vframe.cpp + (vframeStreamCommon::security_get_caller_frame). */ -#if defined(ENABLE_JIT) -# if defined(ENABLE_INTRP) - if (opt_intrp) - ra = intrp_md_stacktrace_get_returnaddress(sp, framesize); - else -# endif - ra = md_stacktrace_get_returnaddress(sp, framesize); -#else - ra = intrp_md_stacktrace_get_returnaddress(sp, framesize); -#endif + /* This is java.lang.reflect.Method.invoke(), skip it. */ - /* get data segment and methodinfo pointer from parent method */ + if (m == method_java_lang_reflect_Method_invoke) + continue; -#if defined(ENABLE_INTRP) - if (opt_intrp) - pv = codegen_findmethod(ra); - else -#endif - { -#if defined(ENABLE_JIT) - pv = md_codegen_findmethod(ra); + /* This is an auxiliary frame, skip it. */ + + if (class_issubclass(c, class_sun_reflect_MagicAccessorImpl)) + continue; #endif - } - m = *((methodinfo **) (pv + MethodPointer)); + /* We reached the requested depth. */ - /* walk the stack */ + if (i >= depth) + return c; -#if defined(ENABLE_INTRP) - if (opt_intrp) - sp = *(u1 **) (sp - framesize); - else -#endif - { -#if defined(__I386__) || defined (__X86_64__) - sp += framesize + SIZEOF_VOID_P; -#else - sp += framesize; -#endif - } - } + i++; } - /* return the stacktracebuffer */ - - return stb; + return NULL; } +#endif + +/* stacktrace_first_nonnull_classloader **************************************** -/* stacktrace_fillInStackTrace ************************************************* + Returns the first non-null (user-defined) classloader on the stack. + If none is found NULL is returned. - Generate a stacktrace from the current thread for - java.lang.VMThrowable.fillInStackTrace. + RETURN: + classloader *******************************************************************************/ -stacktracebuffer *stacktrace_fillInStackTrace(void) +classloader_t *stacktrace_first_nonnull_classloader(void) { - stacktracebuffer *stb; - stacktracebuffer *gcstb; - s4 dumpsize; - CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD - - /* mark start of dump memory area */ - - dumpsize = dump_size(); - - /* create a stacktrace from the current thread */ - - stb = stacktrace_create(THREADOBJECT); - if (!stb) - goto return_NULL; - - /* allocate memory from the GC heap and copy the stacktrace buffer */ - - gcstb = GCNEW(stacktracebuffer); + stackframeinfo_t *sfi; + stackframeinfo_t tmpsfi; + methodinfo *m; + classloader_t *cl; - if (gcstb == NULL) - goto return_NULL; +#if !defined(NDEBUG) + if (opt_DebugStackTrace) + log_println("[stacktrace_first_nonnull_classloader]"); +#endif - gcstb->capacity = stb->capacity; - gcstb->used = stb->used; - gcstb->entries = GCMNEW(stacktrace_entry, stb->used); + /* Get the stackframeinfo of the current thread. */ - if (gcstb->entries == NULL) - goto return_NULL; + sfi = threads_get_current_stackframeinfo(); - MCOPY(gcstb->entries, stb->entries, stacktrace_entry, stb->used); + /* Iterate over the whole stack. */ - /* release dump memory */ + for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi); + stacktrace_stackframeinfo_end_check(&tmpsfi) == false; + stacktrace_stackframeinfo_next(&tmpsfi)) { - dump_release(dumpsize); + m = tmpsfi.code->m; + cl = class_get_classloader(m->clazz); - CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace, - stacktrace_overhead) - return gcstb; - -return_NULL: - dump_release(dumpsize); - - CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace, - stacktrace_overhead) + if (cl != NULL) + return cl; + } return NULL; } @@ -1110,70 +809,81 @@ return_NULL: *******************************************************************************/ -java_objectarray *stacktrace_getClassContext(void) +java_handle_objectarray_t *stacktrace_getClassContext(void) { - stacktracebuffer *stb; - stacktrace_entry *ste; - java_objectarray *oa; - s4 oalength; - s4 i; - s4 dumpsize; + stackframeinfo_t *sfi; + stackframeinfo_t tmpsfi; + int depth; + java_handle_objectarray_t *oa; + java_object_t **data; + int i; + methodinfo *m; + CYCLES_STATS_DECLARE_AND_START - /* mark start of dump memory area */ +#if !defined(NDEBUG) + if (opt_DebugStackTrace) + log_println("[stacktrace_getClassContext]"); +#endif - dumpsize = dump_size(); + sfi = threads_get_current_stackframeinfo(); - /* create a stacktrace for the current thread */ + /* Get the depth of the current stack. */ - stb = stacktrace_create(THREADOBJECT); - if (!stb) - goto return_NULL; + depth = stacktrace_depth(sfi); - /* calculate the size of the Class array */ + /* The first stackframe corresponds to the method whose + implementation calls this native function. We remove that + entry. */ - for (i = 0, oalength = 0; i < stb->used; i++) - if (stb->entries[i].method != NULL) - oalength++; + depth--; + stacktrace_stackframeinfo_fill(&tmpsfi, sfi); + stacktrace_stackframeinfo_next(&tmpsfi); - /* The first entry corresponds to the method whose implementation */ - /* calls stacktrace_getClassContext. We remove that entry. */ + /* Allocate the Class array. */ - ste = &(stb->entries[0]); - ste++; - oalength--; + oa = builtin_anewarray(depth, class_java_lang_Class); - /* allocate the Class array */ + if (oa == NULL) { + CYCLES_STATS_END(stacktrace_getClassContext); - oa = builtin_anewarray(oalength, class_java_lang_Class); - if (!oa) - goto return_NULL; + return NULL; + } - /* fill the Class array from the stacktracebuffer */ + /* Fill the Class array from the stacktrace list. */ - for(i = 0; i < oalength; i++, ste++) { - if (ste->method == NULL) { - i--; - continue; - } + LLNI_CRITICAL_START; - oa->data[i] = (java_objectheader *) ste->method->class; - } + data = LLNI_array_data(oa); - /* release dump memory */ + /* Iterate over the whole stack. */ - dump_release(dumpsize); + i = 0; - CYCLES_STATS_END(stacktrace_getClassContext) + for (; + stacktrace_stackframeinfo_end_check(&tmpsfi) == false; + stacktrace_stackframeinfo_next(&tmpsfi)) { + /* Get methodinfo. */ - return oa; + m = tmpsfi.code->m; -return_NULL: - dump_release(dumpsize); + /* Skip builtin methods. */ + + if (m->flags & ACC_METHOD_BUILTIN) + continue; + + /* Store the class in the array. */ + + data[i] = (java_object_t *) m->clazz; + + i++; + } + + LLNI_CRITICAL_END; CYCLES_STATS_END(stacktrace_getClassContext) - return NULL; + return oa; } @@ -1194,279 +904,411 @@ return_NULL: *******************************************************************************/ -classinfo *stacktrace_getCurrentClass(void) +#if defined(ENABLE_JAVASE) +classinfo *stacktrace_get_current_class(void) { - stacktracebuffer *stb; - stacktrace_entry *ste; - methodinfo *m; - s4 i; - s4 dumpsize; - CYCLES_STATS_DECLARE_AND_START + stackframeinfo_t *sfi; + stackframeinfo_t tmpsfi; + methodinfo *m; - /* mark start of dump memory area */ + CYCLES_STATS_DECLARE_AND_START; - dumpsize = dump_size(); +#if !defined(NDEBUG) + if (opt_DebugStackTrace) + log_println("[stacktrace_get_current_class]"); +#endif - /* create a stacktrace for the current thread */ + /* Get the stackframeinfo of the current thread. */ - stb = stacktrace_create(THREADOBJECT); - if (!stb) - goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */ + sfi = threads_get_current_stackframeinfo(); - /* iterate over all stacktrace entries and find the first suitable - class */ + /* If the stackframeinfo is NULL then FindClass is called through + the Invocation Interface and we return NULL */ - for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) { - m = ste->method; + if (sfi == NULL) { + CYCLES_STATS_END(stacktrace_getCurrentClass); - if (m == NULL) - continue; + return NULL; + } - if (m->class == class_java_security_PrivilegedAction) - goto return_NULL; + /* Iterate over the whole stack. */ + + for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi); + stacktrace_stackframeinfo_end_check(&tmpsfi) == false; + stacktrace_stackframeinfo_next(&tmpsfi)) { + /* Get the methodinfo. */ - if (m->class != NULL) { - dump_release(dumpsize); + m = tmpsfi.code->m; - CYCLES_STATS_END(stacktrace_getCurrentClass) + if (m->clazz == class_java_security_PrivilegedAction) { + CYCLES_STATS_END(stacktrace_getCurrentClass); - return m->class; + return NULL; } - } - /* no Java method found on the stack */ + if (m->clazz != NULL) { + CYCLES_STATS_END(stacktrace_getCurrentClass); -return_NULL: - dump_release(dumpsize); + return m->clazz; + } + } - CYCLES_STATS_END(stacktrace_getCurrentClass) + /* No Java method found on the stack. */ + + CYCLES_STATS_END(stacktrace_getCurrentClass); return NULL; } +#endif /* ENABLE_JAVASE */ -/* stacktrace_getStack ********************************************************* +/* stacktrace_get_stack ******************************************************** Create a 2-dimensional array for java.security.VMAccessControler. RETURN VALUE: the arrary, or - NULL if an exception has been thrown + NULL if an exception has been thrown *******************************************************************************/ -java_objectarray *stacktrace_getStack(void) +#if defined(ENABLE_JAVASE) && defined(WITH_CLASSPATH_GNU) +java_handle_objectarray_t *stacktrace_get_stack(void) { - stacktracebuffer *stb; - stacktrace_entry *ste; - java_objectarray *oa; - java_objectarray *classes; - java_objectarray *methodnames; - classinfo *c; - java_lang_String *str; - s4 i; - s4 dumpsize; + stackframeinfo_t *sfi; + stackframeinfo_t tmpsfi; + int depth; + java_handle_objectarray_t *oa; + java_handle_objectarray_t *classes; + java_handle_objectarray_t *methodnames; + methodinfo *m; + java_handle_t *string; + int i; + CYCLES_STATS_DECLARE_AND_START - /* mark start of dump memory area */ +#if !defined(NDEBUG) + if (opt_DebugStackTrace) + log_println("[stacktrace_get_stack]"); +#endif - dumpsize = dump_size(); + /* Get the stackframeinfo of the current thread. */ - /* create a stacktrace for the current thread */ + sfi = threads_get_current_stackframeinfo(); - stb = stacktrace_create(THREADOBJECT); - if (!stb) - goto return_NULL; + /* Get the depth of the current stack. */ - /* get the first stacktrace entry */ + depth = stacktrace_depth(sfi); - ste = &(stb->entries[0]); + if (depth == 0) + return NULL; - /* allocate all required arrays */ + /* Allocate the required arrays. */ oa = builtin_anewarray(2, arrayclass_java_lang_Object); - if (!oa) + if (oa == NULL) goto return_NULL; - classes = builtin_anewarray(stb->used, class_java_lang_Class); + classes = builtin_anewarray(depth, class_java_lang_Class); - if (!classes) + if (classes == NULL) goto return_NULL; - methodnames = builtin_anewarray(stb->used, class_java_lang_String); + methodnames = builtin_anewarray(depth, class_java_lang_String); - if (!methodnames) + if (methodnames == NULL) goto return_NULL; - /* set up the 2-dimensional array */ + /* Set up the 2-dimensional array. */ - oa->data[0] = (java_objectheader *) classes; - oa->data[1] = (java_objectheader *) methodnames; + array_objectarray_element_set(oa, 0, (java_handle_t *) classes); + array_objectarray_element_set(oa, 1, (java_handle_t *) methodnames); - /* iterate over all stacktrace entries */ + /* Iterate over the whole stack. */ + /* TODO We should use a critical section here to speed things + up. */ - for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) { - c = ste->method->class; + i = 0; - classes->data[i] = (java_objectheader *) c; - str = javastring_new(ste->method->name); + for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi); + stacktrace_stackframeinfo_end_check(&tmpsfi) == false; + stacktrace_stackframeinfo_next(&tmpsfi)) { + /* Get the methodinfo. */ - if (!str) - goto return_NULL; + m = tmpsfi.code->m; - methodnames->data[i] = (java_objectheader *) str; - } + /* Skip builtin methods. */ + + if (m->flags & ACC_METHOD_BUILTIN) + continue; - /* return the 2-dimensional array */ + /* Store the class in the array. */ + /* NOTE: We use a LLNI-macro here, because a classinfo is not + a handle. */ - dump_release(dumpsize); + LLNI_array_direct(classes, i) = (java_object_t *) m->clazz; - CYCLES_STATS_END(stacktrace_getStack) + /* Store the name in the array. */ + + string = javastring_new(m->name); + + if (string == NULL) + goto return_NULL; + + array_objectarray_element_set(methodnames, i, string); + + i++; + } + + CYCLES_STATS_END(stacktrace_get_stack) return oa; return_NULL: - dump_release(dumpsize); - - CYCLES_STATS_END(stacktrace_getStack) + CYCLES_STATS_END(stacktrace_get_stack) return NULL; } +#endif + +/* stacktrace_print_entry **************************************************** -/* stacktrace_print_trace_from_buffer ****************************************** + Print line for a stacktrace entry. - Print the stacktrace of a given stacktracebuffer with CACAO intern - methods (no Java help). This method is used by - stacktrace_dump_trace and builtin_trace_exception. + ARGUMENTS: + m ............ methodinfo of the entry + linenumber ... linenumber of the entry *******************************************************************************/ -static void stacktrace_print_trace_from_buffer(stacktracebuffer *stb) +static void stacktrace_print_entry(methodinfo *m, int32_t linenumber) { - stacktrace_entry *ste; - methodinfo *m; - s4 i; + /* Sanity check. */ - ste = &(stb->entries[0]); + assert(m != NULL); - for (i = 0; i < stb->used; i++, ste++) { - m = ste->method; + printf("\tat "); - printf("\tat "); - utf_display_printable_ascii_classname(m->class->name); - printf("."); - utf_display_printable_ascii(m->name); - utf_display_printable_ascii(m->descriptor); + if (m->flags & ACC_METHOD_BUILTIN) + printf("NULL"); + else + utf_display_printable_ascii_classname(m->clazz->name); - if (m->flags & ACC_NATIVE) { - puts("(Native Method)"); + printf("."); + utf_display_printable_ascii(m->name); + utf_display_printable_ascii(m->descriptor); - } else { + if (m->flags & ACC_NATIVE) { + puts("(Native Method)"); + } + else { + if (m->flags & ACC_METHOD_BUILTIN) { + puts("(builtin)"); + } + else { printf("("); - utf_display_printable_ascii(m->class->sourcefile); - printf(":%d)\n", (u4) ste->linenumber); + utf_display_printable_ascii(m->clazz->sourcefile); + printf(":%d)\n", linenumber); } } - /* just to be sure */ - fflush(stdout); } -/* stacktrace_dump_trace ******************************************************* +/* stacktrace_print ************************************************************ + + Print the given stacktrace with CACAO intern methods only (no Java + code required). - This method is call from signal_handler_sigusr1 to dump the - stacktrace of the current thread to stdout. + This method is used by stacktrace_dump_trace and + builtin_trace_exception. + + IN: + st ... stacktrace to print *******************************************************************************/ -void stacktrace_dump_trace(void) +void stacktrace_print(stacktrace_t *st) { - stacktracebuffer *stb; - s4 dumpsize; + stacktrace_entry_t *ste; + methodinfo *m; + int32_t linenumber; + int i; -#if 0 - /* get methodinfo pointer from data segment */ + ste = &(st->entries[0]); - m = *((methodinfo **) (pv + MethodPointer)); + for (i = 0; i < st->length; i++, ste++) { + m = ste->code->m; - /* get current stackframe info pointer */ + /* Get the line number. */ - psfi = STACKFRAMEINFO; + linenumber = linenumbertable_linenumber_for_pc(&m, ste->code, ste->pc); - /* fill new stackframe info structure */ + stacktrace_print_entry(m, linenumber); + } +} - sfi->prev = *psfi; - sfi->method = NULL; - sfi->pv = NULL; - sfi->sp = sp; - sfi->ra = ra; - /* store new stackframe info pointer */ +/* stacktrace_print_current **************************************************** + + Print the current stacktrace of the current thread. + + NOTE: This function prints all frames of the stacktrace and does + not skip frames like stacktrace_get. + +*******************************************************************************/ + +void stacktrace_print_current(void) +{ + stackframeinfo_t *sfi; + stackframeinfo_t tmpsfi; + codeinfo *code; + methodinfo *m; + int32_t linenumber; + + sfi = threads_get_current_stackframeinfo(); + + if (sfi == NULL) { + puts("\t<>"); + fflush(stdout); + return; + } + + for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi); + stacktrace_stackframeinfo_end_check(&tmpsfi) == false; + stacktrace_stackframeinfo_next(&tmpsfi)) { + /* Get the methodinfo. */ + + code = tmpsfi.code; + m = code->m; + + /* Get the line number. */ + + linenumber = linenumbertable_linenumber_for_pc(&m, code, tmpsfi.xpc); + + stacktrace_print_entry(m, linenumber); + } +} - *psfi = sfi; -#endif - /* mark start of dump memory area */ +/* stacktrace_print_of_thread ************************************************** - dumpsize = dump_size(); + Print the current stacktrace of the given thread. - /* create a stacktrace for the current thread */ + ARGUMENTS: + t ... thread - stb = stacktrace_create(THREADOBJECT); +*******************************************************************************/ - /* print stacktrace */ +#if defined(ENABLE_THREADS) +void stacktrace_print_of_thread(threadobject *t) +{ + stackframeinfo_t *sfi; + stackframeinfo_t tmpsfi; + codeinfo *code; + methodinfo *m; + int32_t linenumber; - if (stb) { - stacktrace_print_trace_from_buffer(stb); + /* Build a stacktrace for the passed thread. */ - } else { + sfi = t->_stackframeinfo; + + if (sfi == NULL) { puts("\t<>"); fflush(stdout); + return; } - dump_release(dumpsize); + for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi); + stacktrace_stackframeinfo_end_check(&tmpsfi) == false; + stacktrace_stackframeinfo_next(&tmpsfi)) { + /* Get the methodinfo. */ + + code = tmpsfi.code; + m = code->m; + + /* Get the line number. */ + + linenumber = linenumbertable_linenumber_for_pc(&m, code, tmpsfi.xpc); + + stacktrace_print_entry(m, linenumber); + } } +#endif -/* stacktrace_print_trace ****************************************************** +/* stacktrace_print_exception ************************************************** - Print the stacktrace of a given exception. More or less a wrapper - to stacktrace_print_trace_from_buffer. + Print the stacktrace of a given exception (more or less a wrapper + to stacktrace_print). + + IN: + h ... handle of exception to print *******************************************************************************/ -void stacktrace_print_trace(java_objectheader *xptr) +void stacktrace_print_exception(java_handle_t *h) { - java_lang_Throwable *t; - java_lang_VMThrowable *vmt; - stacktracebuffer *stb; + java_lang_Throwable *o; + +#if defined(WITH_CLASSPATH_GNU) + java_lang_VMThrowable *vmt; +#endif - t = (java_lang_Throwable *) xptr; + java_lang_Object *backtrace; + java_handle_bytearray_t *ba; + stacktrace_t *st; - if (t == NULL) + o = (java_lang_Throwable *) h; + + if (o == NULL) return; /* now print the stacktrace */ - vmt = t->vmState; - stb = (stacktracebuffer *) vmt->vmData; +#if defined(WITH_CLASSPATH_GNU) + + LLNI_field_get_ref(o, vmState, vmt); + LLNI_field_get_ref(vmt, vmdata, backtrace); + +#elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1) + + LLNI_field_get_ref(o, backtrace, backtrace); + +#else +# error unknown classpath configuration +#endif + + ba = (java_handle_bytearray_t *) backtrace; + + /* Sanity check. */ + + assert(ba != NULL); + + /* We need a critical section here as we use the byte-array data + pointer directly. */ + + LLNI_CRITICAL_START; + + st = (stacktrace_t *) LLNI_array_data(ba); + + stacktrace_print(st); - stacktrace_print_trace_from_buffer(stb); + LLNI_CRITICAL_END; } #if defined(ENABLE_CYCLES_STATS) void stacktrace_print_cycles_stats(FILE *file) { - CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file); - CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file); - CYCLES_STATS_PRINT(stacktrace_getClassContext ,file); - CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file); - CYCLES_STATS_PRINT(stacktrace_getStack ,file); + CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead, file); + CYCLES_STATS_PRINT(stacktrace_get, file); + CYCLES_STATS_PRINT(stacktrace_getClassContext , file); + CYCLES_STATS_PRINT(stacktrace_getCurrentClass , file); + CYCLES_STATS_PRINT(stacktrace_get_stack, file); } #endif