X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fstacktrace.c;h=a6854317917c7822a369e1552b2637c03827b19c;hb=0e53ae4c44c26d87210b3b3c295ef169864e7a79;hp=5055239266d1dea7a0d0f0aedbe3a1c9b8a4d75f;hpb=99994e1f54a7ad28c5b166b936a706e7c637d195;p=cacao.git diff --git a/src/vm/jit/stacktrace.c b/src/vm/jit/stacktrace.c index 505523926..a68543179 100644 --- a/src/vm/jit/stacktrace.c +++ b/src/vm/jit/stacktrace.c @@ -22,14 +22,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - $Id: stacktrace.c 7652 2007-04-03 14:23:16Z twisti $ - */ #include "config.h" #include +#include #include #include @@ -42,6 +41,7 @@ #include "vm/global.h" /* required here for native includes */ #include "native/jni.h" +#include "native/llni.h" #include "native/include/java_lang_Throwable.h" #if defined(WITH_CLASSPATH_GNU) @@ -56,6 +56,7 @@ #include "toolbox/logging.h" +#include "vm/array.h" #include "vm/builtin.h" #include "vm/cycles-stats.h" #include "vm/exceptions.h" @@ -64,6 +65,7 @@ #include "vm/jit/asmpart.h" #include "vm/jit/codegen-common.h" +#include "vm/jit/linenumbertable.h" #include "vm/jit/methodheader.h" #include "vmcore/class.h" @@ -73,7 +75,7 @@ /* global variables ***********************************************************/ #if !defined(ENABLE_THREADS) -stackframeinfo *_no_threads_stackframeinfo = NULL; +stackframeinfo_t *_no_threads_stackframeinfo = NULL; #endif CYCLES_STATS_DECLARE(stacktrace_overhead ,100,1) @@ -83,83 +85,22 @@ CYCLES_STATS_DECLARE(stacktrace_getCurrentClass ,40,5000) CYCLES_STATS_DECLARE(stacktrace_getStack ,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; - codeinfo *code; - - /* 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_get_pv_from_pc(ra); - else + stackframeinfo_t **psfi; + codeinfo *code; +#if !defined(__I386__) && !defined(__X86_64__) && !defined(__S390__) && !defined(__M68K__) + bool isleafmethod; #endif - { #if defined(ENABLE_JIT) - pv = md_codegen_get_pv_from_pc(ra); -#endif - } - } - - /* get codeinfo pointer from data segment */ - - code = *((codeinfo **) (pv + CodeinfoPointer)); - - /* For asm_vm_call_method the codeinfo pointer is NULL. */ - - m = (code == NULL) ? NULL : code->m; - - /* 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) */ - - -/* 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__) && !defined(__S390__) - bool isleafmethod; -#endif -#if defined(ENABLE_JIT) - s4 framesize; + s4 framesize; #endif /* get current stackframe info pointer */ @@ -186,15 +127,23 @@ void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv, } } + /* 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__) || defined(__S390__) +# 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. */ @@ -218,76 +167,79 @@ void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv, # if defined(ENABLE_INTRP) } # endif -#endif /* defined(ENABLE_JIT) */ +#endif - /* fill new stackframe info structure */ + /* 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. */ - sfi->prev = *psfi; - sfi->method = NULL; - sfi->pv = pv; - sfi->sp = sp; - sfi->ra = ra; - sfi->xpc = xpc; + if (xpc == NULL) { + xpc = (void *) (((intptr_t) ra) - 1); + } + + /* Fill new stackframeinfo structure. */ + + sfi->prev = *psfi; + 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 - /* store new stackframe info pointer */ + /* Store new stackframeinfo pointer. */ *psfi = sfi; + + /* 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. */ + + THREAD_NATIVEWORLD_ENTER; } -/* stacktrace_create_native_stackframeinfo ************************************* +/* stacktrace_stackframeinfo_remove ******************************************** - Creates a stackframe info structure for a native stub. + Remove the given stackframeinfo from the chain in the current + thread. *******************************************************************************/ -void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv, - u1 *sp, u1 *ra) +void stacktrace_stackframeinfo_remove(stackframeinfo_t *sfi) { - stackframeinfo **psfi; - methodinfo *m; - codeinfo *code; - - /* get codeinfo pointer from data segment */ + stackframeinfo_t **psfi; - code = *((codeinfo **) (pv + CodeinfoPointer)); + /* clear the native world flag for the current thread */ + /* ATTENTION: Clear this flag _before_ removing the stackframe info */ - /* For asm_vm_call_method the codeinfo pointer is NULL. */ - - m = (code == NULL) ? NULL : code->m; + THREAD_NATIVEWORLD_EXIT; /* 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 ******************************************** - - Remove the topmost stackframeinfo in the current thread. - -*******************************************************************************/ - -void stacktrace_remove_stackframeinfo(stackframeinfo *sfi) -{ - stackframeinfo **psfi; - - /* get current stackframe info pointer */ - - psfi = &STACKFRAMEINFO; +#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 /* restore the old pointer */ @@ -295,23 +247,33 @@ void stacktrace_remove_stackframeinfo(stackframeinfo *sfi) } -/* stacktrace_add_entry ******************************************************** +/* stacktrace_entry_add ******************************************************** Adds a new entry to the stacktrace buffer. *******************************************************************************/ -static void stacktrace_add_entry(stacktracebuffer *stb, methodinfo *m, u2 line) +static inline stacktracebuffer *stacktrace_entry_add(stacktracebuffer *stb, methodinfo *m, u2 line) { stacktrace_entry *ste; + u4 stb_size_old; + u4 stb_size_new; /* check if we already reached the buffer capacity */ if (stb->used >= stb->capacity) { + /* calculate size of stacktracebuffer */ + + stb_size_old = sizeof(stacktracebuffer) + + sizeof(stacktrace_entry) * stb->capacity - + sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_DEFAULT; + + stb_size_new = stb_size_old + + sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_INCREMENT; + /* reallocate new memory */ - stb->entries = DMREALLOC(stb->entries, stacktrace_entry, stb->capacity, - stb->capacity + STACKTRACE_CAPACITY_INCREMENT); + stb = DMREALLOC(stb, u1, stb_size_old, stb_size_new); /* set new buffer capacity */ @@ -328,339 +290,370 @@ static void stacktrace_add_entry(stacktracebuffer *stb, methodinfo *m, u2 line) /* increase entries used count */ stb->used += 1; + + return stb; } -/* stacktrace_add_method ******************************************************* +/* stacktrace_method_add ******************************************************* - Add stacktrace entries[1] for the given method to the stacktrace buffer. + Add stacktrace entries[1] for the given method to the stacktrace + buffer. 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 - + stb....stacktracebuffer to fill + sfi....current stackframeinfo OUT: - true, if stacktrace entries were successfully created, false otherwise. + stacktracebuffer after possible reallocation. [1] In case of inlined methods there may be more than one stacktrace entry for a codegen-level method. (see doc/inlining_stacktrace.txt) *******************************************************************************/ -static bool stacktrace_add_method(stacktracebuffer *stb, methodinfo *m, u1 *pv, - u1 *pc) +static inline stacktracebuffer *stacktrace_method_add(stacktracebuffer *stb, stackframeinfo_t *sfi) { - codeinfo *code; /* compiled realization of method */ - s4 linenumber; + codeinfo *code; + void *pv; + void *xpc; + methodinfo *m; + int32_t linenumber; + + /* Get values from the stackframeinfo. */ + + code = sfi->code; + pv = sfi->pv; + xpc = sfi->xpc; - /* find the realization of the method the pc is in */ + m = code->m; - code = *((codeinfo **) (pv + CodeinfoPointer)); + /* Skip builtin methods. */ - /* search the line number table */ + if (m->flags & ACC_METHOD_BUILTIN) + return stb; + + /* Search the line number table. */ - linenumber = dseg_get_linenumber_from_pc(&m, pv, pc); + linenumber = linenumbertable_linenumber_for_pc(&m, code, xpc); - /* now add a new entry to the staktrace */ + /* Add a new entry to the staktrace. */ - stacktrace_add_entry(stb, m, linenumber); + stb = stacktrace_entry_add(stb, m, linenumber); - return true; + return stb; } -/* stacktrace_create *********************************************************** +/* stacktrace_stackframeinfo_fill ********************************************** - Generates a stacktrace from the thread passed into a - stacktracebuffer. The stacktracebuffer is allocated on the - dump memory. + Fill the temporary stackframeinfo structure with the values given + in sfi. - RETURN VALUE: - pointer to the stacktracebuffer, or - NULL if there is no stacktrace available for the - given thread. + IN: + tmpsfi ... temporary stackframeinfo + sfi ...... stackframeinfo to be used in the next iteration *******************************************************************************/ -stacktracebuffer *stacktrace_create(threadobject* thread) +static inline void stacktrace_stackframeinfo_fill(stackframeinfo_t *tmpsfi, stackframeinfo_t *sfi) { - stacktracebuffer *stb; - stackframeinfo *sfi; - methodinfo *m; - codeinfo *code; - u1 *pv; - u1 *sp; - u4 framesize; - u1 *ra; - u1 *xpc; + /* Sanity checks. */ - /* prevent compiler warnings */ + assert(tmpsfi != NULL); + assert(sfi != NULL); - pv = NULL; - sp = NULL; - ra = NULL; + /* Fill the temporary stackframeinfo. */ - /* create a stacktracebuffer in dump memory */ + tmpsfi->code = sfi->code; + tmpsfi->pv = sfi->pv; + tmpsfi->sp = sfi->sp; + tmpsfi->ra = sfi->ra; + tmpsfi->xpc = sfi->xpc; - stb = DNEW(stacktracebuffer); + /* Set the previous stackframe info of the temporary one to the + next in the chain. */ - stb->capacity = STACKTRACE_CAPACITY_DEFAULT; - stb->used = 0; - stb->entries = DMNEW(stacktrace_entry, STACKTRACE_CAPACITY_DEFAULT); + tmpsfi->prev = sfi->prev; +} - /* The first element in the stackframe chain must always be a - native stackframeinfo (VMThrowable.fillInStackTrace is a native - function). */ - /* We don't use the STACKFRAMEINFO macro here, as we have to use - the passed thread. */ +/* stacktrace_stackframeinfo_next ********************************************** -#if defined(ENABLE_THREADS) - sfi = thread->_stackframeinfo; -#else - sfi = _no_threads_stackframeinfo; -#endif + Walk the stack (or the stackframeinfo-chain) to the next method and + return the new stackframe values in the temporary stackframeinfo + passed. -#define PRINTMETHODS 0 + IN: + tmpsfi ... temporary stackframeinfo of current method -#if PRINTMETHODS - printf("\n\nfillInStackTrace start:\n"); - fflush(stdout); -#endif +*******************************************************************************/ - /* Loop while we have a method pointer (asm_calljavafunction has - NULL) or there is a stackframeinfo in the chain. */ +static inline void stacktrace_stackframeinfo_next(stackframeinfo_t *tmpsfi) +{ + codeinfo *code; + void *pv; + void *sp; + void *ra; + void *xpc; + uint32_t framesize; + stackframeinfo_t *prevsfi; - m = NULL; + /* Sanity check. */ - while ((m != NULL) || (sfi != NULL)) { - /* m == NULL should only happen for the first time and inline - stackframe infos, like from the exception stubs or the - patcher wrapper. */ + assert(tmpsfi != NULL); - if (m == NULL) { - /* for native stub stackframe infos, pv is always NULL */ + /* Get values from the stackframeinfo. */ - if (sfi->pv == NULL) { - /* get methodinfo, sp and ra from the current stackframe info */ + code = tmpsfi->code; + pv = tmpsfi->pv; + sp = tmpsfi->sp; + ra = tmpsfi->ra; + xpc = tmpsfi->xpc; - m = sfi->method; - sp = sfi->sp; /* sp of parent Java function */ - ra = sfi->ra; + /* Get the current stack frame size. */ - if (m) - stacktrace_add_entry(stb, m, 0); + framesize = *((uint32_t *) (((intptr_t) pv) + FrameSize)); -#if PRINTMETHODS - printf("ra=%p sp=%p, ", ra, sp); - method_print(m); - printf(": native stub\n"); - fflush(stdout); + /* 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). */ + +#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 - /* This is an native stub stackframe info, so we can - get the parent pv from the return address - (ICMD_INVOKE*). */ + + /* Get the PV for the parent Java method. */ #if defined(ENABLE_INTRP) - if (opt_intrp) - pv = codegen_get_pv_from_pc(ra); - else + if (opt_intrp) + pv = codegen_get_pv_from_pc(ra); + else #endif - { + { #if defined(ENABLE_JIT) - pv = md_codegen_get_pv_from_pc(ra); +# 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 methodinfo pointer from parent data segment */ + /* Get the codeinfo pointer for the parent Java method. */ - code = *((codeinfo **) (pv + CodeinfoPointer)); + code = code_get_codeinfo_for_pv(pv); - /* For asm_vm_call_method the codeinfo pointer is - NULL. */ + /* Calculate the SP for the parent Java method. */ - m = (code == NULL) ? NULL : code->m; +#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 + } - } 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!!! */ + /* 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. */ - /* get methodinfo, sp and ra from the current stackframe info */ + if (code == NULL) { + prevsfi = tmpsfi->prev; - 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 */ + /* 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. */ -#if PRINTMETHODS - printf("ra=%p sp=%p, ", ra, sp); - printf("NULL: inline stub\n"); - fflush(stdout); -#endif + if (prevsfi == NULL) { + tmpsfi->code = NULL; + tmpsfi->prev = NULL; + return; + } - /* get methodinfo from current Java method */ + /* Fill the temporary stackframeinfo with the new values. */ - code = *((codeinfo **) (pv + CodeinfoPointer)); + 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); + } +} - /* For asm_vm_call_method the codeinfo pointer is - NULL. */ - m = (code == NULL) ? NULL : code->m; +/* stacktrace_stackframeinfo_end_check ***************************************** - /* if m == NULL, this is a asm_calljavafunction call */ + Check if we reached the end of the stacktrace. - if (m != NULL) { -#if PRINTMETHODS - printf("ra=%p sp=%p, ", ra, sp); - method_print(m); - printf(": inline stub parent"); - fflush(stdout); -#endif + IN: + tmpsfi ... temporary stackframeinfo of current method -#if defined(ENABLE_INTRP) - if (!opt_intrp) { -#endif + RETURN: + true .... the end is reached + false ... the end is not reached - /* add the method to the stacktrace */ +*******************************************************************************/ - stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) xpc)); +static inline bool stacktrace_stackframeinfo_end_check(stackframeinfo_t *tmpsfi) +{ + /* Sanity check. */ - /* get the current stack frame size */ + assert(tmpsfi != NULL); - framesize = *((u4 *) (pv + FrameSize)); + if ((tmpsfi->code == NULL) && (tmpsfi->prev == NULL)) + return true; -#if PRINTMETHODS - printf(", framesize=%d\n", framesize); - fflush(stdout); -#endif + return false; +} - /* Set stack pointer to stackframe of parent Java - function of the current Java function. */ -#if defined(__I386__) || defined (__X86_64__) - sp += framesize + SIZEOF_VOID_P; -#elif defined(__SPARC_64__) - sp = md_get_framepointer(sp); -#else - sp += framesize; -#endif +/* stacktrace_create *********************************************************** - /* get data segment and methodinfo pointer from - parent method */ + Generates a stacktrace from the thread passed into a + stacktracebuffer. The stacktracebuffer is allocated on the + dump memory. + + NOTE: The first element in the stackframe chain must always be a + native stackframeinfo (e.g. VMThrowable.fillInStackTrace() is + a native function). -#if defined(ENABLE_JIT) - pv = md_codegen_get_pv_from_pc(ra); -#endif + RETURN VALUE: + pointer to the stacktracebuffer, or + NULL if there is no stacktrace available for the + given thread. - code = *((codeinfo **) (pv + CodeinfoPointer)); +*******************************************************************************/ - /* For asm_vm_call_method the codeinfo pointer is - NULL. */ +stacktracebuffer *stacktrace_create(stackframeinfo_t *sfi) +{ + stacktracebuffer *stb; + stackframeinfo_t tmpsfi; + bool skip_fillInStackTrace; + bool skip_init; - m = (code == NULL) ? NULL : code->m; + skip_fillInStackTrace = true; + skip_init = true; -#if defined(ENABLE_INTRP) - } -#endif - } -#if PRINTMETHODS - else { - printf("ra=%p sp=%p, ", ra, sp); - printf("asm_calljavafunction\n"); - fflush(stdout); - } -#endif - } + /* Create a stacktracebuffer in dump memory. */ - /* get previous stackframeinfo in the chain */ + stb = DNEW(stacktracebuffer); - sfi = sfi->prev; + stb->capacity = STACKTRACE_CAPACITY_DEFAULT; + stb->used = 0; - } else { -#if PRINTMETHODS - printf("ra=%p sp=%p, ", ra, sp); - method_print(m); - printf(": JIT"); - fflush(stdout); +#if !defined(NDEBUG) + if (opt_DebugStackTrace) { + printf("\n\n---> stacktrace creation start (fillInStackTrace):\n"); + fflush(stdout); + } #endif - /* JIT method found, add it to the stacktrace (we subtract - 1 from the return address since it points the the - instruction after call). */ - - stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1); - - /* get the current stack frame size */ + /* Put the data from the stackframeinfo into a temporary one. */ - framesize = *((u4 *) (pv + FrameSize)); + /* XXX This is not correct, but a workaround for threads-dump for + now. */ +/* assert(sfi != NULL); */ + if (sfi == NULL) + return NULL; -#if PRINTMETHODS - printf(", framesize=%d\n", framesize); - fflush(stdout); + /* Iterate till we're done. */ + + for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi); + stacktrace_stackframeinfo_end_check(&tmpsfi) == false; + stacktrace_stackframeinfo_next(&tmpsfi)) { +#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 - /* get return address of current stack frame */ + /* This logic is taken from + hotspot/src/share/vm/classfile/javaClasses.cpp + (java_lang_Throwable::fill_in_stack_trace). */ -#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 + if (skip_fillInStackTrace == true) { + /* Check "fillInStackTrace" only once, so we negate the + flag after the first time check. */ - /* get data segment and methodinfo pointer from parent method */ +#if defined(WITH_CLASSPATH_GNU) + /* For GNU Classpath we also need to skip + VMThrowable.fillInStackTrace(). */ -#if defined(ENABLE_INTRP) - if (opt_intrp) - pv = codegen_get_pv_from_pc(ra); - else + if ((tmpsfi.code->m->class == class_java_lang_VMThrowable) && + (tmpsfi.code->m->name == utf_fillInStackTrace)) + continue; #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 - } - code = *((codeinfo **) (pv + CodeinfoPointer)); + skip_fillInStackTrace = false; - /* For asm_vm_call_method the codeinfo pointer is NULL. */ + if (tmpsfi.code->m->name == utf_fillInStackTrace) + continue; + } - m = (code == NULL) ? NULL : code->m; + /* 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. */ - /* walk the stack */ + if (skip_init == true) { + if (tmpsfi.code->m->name == utf_init) { +/* throwable->is_a(method->method_holder())) { */ + continue; + } + else { + /* If no "Throwable.init()" method found, we stop + checking it next time. */ -#if defined(ENABLE_INTRP) - if (opt_intrp) - sp = *(u1 **) (sp - framesize); - else -#endif - { -#if defined(__I386__) || defined (__X86_64__) || defined (__M68K__) - sp += framesize + SIZEOF_VOID_P; -#elif defined(__SPARC_64__) - /* already has the new sp */ -#else - sp += framesize; -#endif - } + skip_init = false; + } } + + /* Add this method to the stacktrace. */ + + stb = stacktrace_method_add(stb, &tmpsfi); + } + +#if !defined(NDEBUG) + if (opt_DebugStackTrace) { + printf("---> stacktrace creation finished.\n\n"); + fflush(stdout); } +#endif /* return the stacktracebuffer */ @@ -678,12 +671,12 @@ stacktracebuffer *stacktrace_create(threadobject* thread) *******************************************************************************/ -stacktracecontainer *stacktrace_fillInStackTrace(void) +java_handle_bytearray_t *stacktrace_fillInStackTrace(void) { - stacktracebuffer *stb; - stacktracecontainer *gcstc; - s4 gcstc_size; - s4 dumpsize; + stacktracebuffer *stb; + java_handle_bytearray_t *ba; + s4 ba_size; + s4 dumpsize; CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD /* mark start of dump memory area */ @@ -692,26 +685,23 @@ stacktracecontainer *stacktrace_fillInStackTrace(void) /* create a stacktrace from the current thread */ - stb = stacktrace_create(THREADOBJECT); - if (!stb) + stb = stacktrace_create(STACKFRAMEINFO); + + if (stb == NULL) goto return_NULL; /* allocate memory from the GC heap and copy the stacktrace buffer */ - /* ATTENTION: use stacktracecontainer for this and make it look like - an array */ + /* ATTENTION: use a bytearray for this to not confuse the GC */ - gcstc_size = sizeof(stacktracebuffer) + - sizeof(stacktrace_entry) * stb->used; - gcstc = (stacktracecontainer *) builtin_newarray_byte(gcstc_size); + ba_size = sizeof(stacktracebuffer) + + sizeof(stacktrace_entry) * stb->used - + sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_DEFAULT; + ba = builtin_newarray_byte(ba_size); - if (gcstc == NULL) + if (ba == NULL) goto return_NULL; - gcstc->stb.capacity = stb->capacity; - gcstc->stb.used = stb->used; - gcstc->stb.entries = gcstc->data; - - MCOPY(gcstc->data, stb->entries, stacktrace_entry, stb->used); + MCOPY(LLNI_array_data(ba), stb, u1, ba_size); /* release dump memory */ @@ -719,7 +709,7 @@ stacktracecontainer *stacktrace_fillInStackTrace(void) CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace, stacktrace_overhead) - return gcstc; + return ba; return_NULL: dump_release(dumpsize); @@ -741,14 +731,14 @@ 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; + stacktracebuffer *stb; + stacktrace_entry *ste; + java_handle_objectarray_t *oa; + s4 oalength; + s4 i; + s4 dumpsize; CYCLES_STATS_DECLARE_AND_START /* mark start of dump memory area */ @@ -757,8 +747,9 @@ java_objectarray *stacktrace_getClassContext(void) /* create a stacktrace for the current thread */ - stb = stacktrace_create(THREADOBJECT); - if (!stb) + stb = stacktrace_create(STACKFRAMEINFO); + + if (stb == NULL) goto return_NULL; /* calculate the size of the Class array */ @@ -788,7 +779,7 @@ java_objectarray *stacktrace_getClassContext(void) continue; } - oa->data[i] = (java_objectheader *) ste->method->class; + LLNI_array_direct(oa, i) = (java_object_t *) ste->method->class; } /* release dump memory */ @@ -841,8 +832,9 @@ classinfo *stacktrace_getCurrentClass(void) /* create a stacktrace for the current thread */ - stb = stacktrace_create(THREADOBJECT); - if (!stb) + stb = stacktrace_create(STACKFRAMEINFO); + + if (stb == NULL) goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */ /* iterate over all stacktrace entries and find the first suitable @@ -889,17 +881,17 @@ return_NULL: *******************************************************************************/ #if defined(ENABLE_JAVASE) -java_objectarray *stacktrace_getStack(void) +java_handle_objectarray_t *stacktrace_getStack(void) { - stacktracebuffer *stb; - stacktrace_entry *ste; - java_objectarray *oa; - java_objectarray *classes; - java_objectarray *methodnames; - classinfo *c; - java_objectheader *string; - s4 i; - s4 dumpsize; + stacktracebuffer *stb; + stacktrace_entry *ste; + java_handle_objectarray_t *oa; + java_handle_objectarray_t *classes; + java_handle_objectarray_t *methodnames; + classinfo *c; + java_handle_t *string; + s4 i; + s4 dumpsize; CYCLES_STATS_DECLARE_AND_START /* mark start of dump memory area */ @@ -908,7 +900,7 @@ java_objectarray *stacktrace_getStack(void) /* create a stacktrace for the current thread */ - stb = stacktrace_create(THREADOBJECT); + stb = stacktrace_create(STACKFRAMEINFO); if (stb == NULL) goto return_NULL; @@ -936,22 +928,22 @@ java_objectarray *stacktrace_getStack(void) /* 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 */ for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) { c = ste->method->class; - classes->data[i] = (java_objectheader *) c; + LLNI_array_direct(classes, i) = (java_object_t *) c; string = javastring_new(ste->method->name); if (string == NULL) goto return_NULL; - methodnames->data[i] = string; + array_objectarray_element_set(methodnames, i, string); } /* return the 2-dimensional array */ @@ -1013,56 +1005,23 @@ void stacktrace_print_trace_from_buffer(stacktracebuffer *stb) } -/* stacktrace_dump_trace ******************************************************* - - This method is call from signal_handler_sigusr1 to dump the - stacktrace of the current thread to stdout. - -*******************************************************************************/ - -void stacktrace_dump_trace(threadobject *thread) -{ - stacktracebuffer *stb; - s4 dumpsize; - - /* mark start of dump memory area */ - - dumpsize = dump_size(); - - /* create a stacktrace for the current thread */ - - stb = stacktrace_create(thread); - - /* print stacktrace */ - - if (stb != NULL) - stacktrace_print_trace_from_buffer(stb); - else { - puts("\t<>"); - fflush(stdout); - } - - dump_release(dumpsize); -} - - -/* stacktrace_print_trace ****************************************************** +/* stacktrace_print_exception ************************************************** Print the stacktrace of a given exception. More or less a wrapper to stacktrace_print_trace_from_buffer. *******************************************************************************/ -void stacktrace_print_trace(java_objectheader *xptr) +void stacktrace_print_exception(java_handle_t *h) { - java_lang_Throwable *t; + java_lang_Throwable *t; #if defined(WITH_CLASSPATH_GNU) - java_lang_VMThrowable *vmt; + java_lang_VMThrowable *vmt; #endif - stacktracecontainer *stc; - stacktracebuffer *stb; + java_handle_bytearray_t *ba; + stacktracebuffer *stb; - t = (java_lang_Throwable *) xptr; + t = (java_lang_Throwable *) h; if (t == NULL) return; @@ -1070,14 +1029,21 @@ void stacktrace_print_trace(java_objectheader *xptr) /* now print the stacktrace */ #if defined(WITH_CLASSPATH_GNU) - vmt = t->vmState; - stc = (stacktracecontainer *) vmt->vmData; - stb = &(stc->stb); -#elif defined(WITH_CLASSPATH_CLDC1_1) - stc = (stacktracecontainer *) t->backtrace; - stb = &(stc->stb); + + LLNI_field_get_ref(t, vmState, vmt); + LLNI_field_get_ref(vmt, vmData, ba); + +#elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1) + + LLNI_field_get_ref(t, backtrace, ba); + +#else +# error unknown classpath configuration #endif + assert(ba); + stb = (stacktracebuffer *) LLNI_array_data(ba); + stacktrace_print_trace_from_buffer(stb); }