X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fstacktrace.c;h=b8847deb3ad31d9638d5ffd242b252900d2a8437;hb=caf4bfb972a703ceeaa4bdf5afb820bce15fd7e6;hp=0e3e4df10794a726d9d935bb0f2e52eca0545847;hpb=72e4b7fbfc23c079318a02b646e9b2c6f5c5abca;p=cacao.git diff --git a/src/vm/jit/stacktrace.c b/src/vm/jit/stacktrace.c index 0e3e4df10..b8847deb3 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 7343 2007-02-13 02:36:29Z ajordan $ - */ #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,128 +85,27 @@ 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); + s4 framesize; #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_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_get_pv_from_pc(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__) && !defined(__S390__) - bool isleafmethod; -#endif -#if defined(ENABLE_JIT) - s4 framesize; -#endif - - /* get current stackframe info pointer */ - - psfi = STACKFRAMEINFO; + psfi = &STACKFRAMEINFO; /* sometimes we don't have pv handy (e.g. in asmpart.S: L_asm_call_jit_compiler_exception or in the interpreter). */ @@ -226,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. */ @@ -258,353 +167,113 @@ 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; - codeinfo *code; - - /* 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; - - /* get current stackframe info pointer */ +#endif - psfi = STACKFRAMEINFO; + /* 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. */ - /* fill new stackframe info structure */ + if (xpc == NULL) { + xpc = (void *) (((intptr_t) ra) - 1); + } - sfi->prev = *psfi; - sfi->method = m; - sfi->pv = NULL; - sfi->sp = sp; - sfi->ra = ra; - sfi->xpc = NULL; + /* 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; -} - - -/* 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; - - /* restore the old pointer */ - - *psfi = sfi->prev; -} - - -/* stacktrace_inline_arithmeticexception *************************************** - - Creates an ArithemticException for inline stub. + /* 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. */ -*******************************************************************************/ - -java_objectheader *stacktrace_inline_arithmeticexception(u1 *pv, u1 *sp, - u1 *ra, u1 *xpc) -{ - stackframeinfo sfi; - java_objectheader *o; - - /* create stackframeinfo */ - - stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc); - - /* create exception */ - - o = exceptions_new_arithmeticexception(); - - /* remove stackframeinfo */ - - stacktrace_remove_stackframeinfo(&sfi); - - return o; + THREAD_NATIVEWORLD_ENTER; } -/* stacktrace_inline_arrayindexoutofboundsexception **************************** +/* stacktrace_stackframeinfo_remove ******************************************** - Creates an ArrayIndexOutOfBoundsException for inline stub. + Remove the given stackframeinfo from the chain in the current + thread. *******************************************************************************/ -java_objectheader *stacktrace_inline_arrayindexoutofboundsexception(u1 *pv, - u1 *sp, - u1 *ra, - u1 *xpc, - s4 index) +void stacktrace_stackframeinfo_remove(stackframeinfo_t *sfi) { - stackframeinfo sfi; - java_objectheader *o; - - /* create stackframeinfo */ - - stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc); + stackframeinfo_t **psfi; - /* create exception */ + /* clear the native world flag for the current thread */ + /* ATTENTION: Clear this flag _before_ removing the stackframe info */ - o = exceptions_new_arrayindexoutofboundsexception(index); + THREAD_NATIVEWORLD_EXIT; - /* remove stackframeinfo */ - - stacktrace_remove_stackframeinfo(&sfi); - - return o; -} - - -/* stacktrace_inline_arraystoreexception *************************************** - - Creates an ArrayStoreException for inline stub. - -*******************************************************************************/ - -java_objectheader *stacktrace_inline_arraystoreexception(u1 *pv, u1 *sp, u1 *ra, - u1 *xpc) -{ - stackframeinfo sfi; - java_objectheader *o; - - /* create stackframeinfo */ - - stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc); - - /* create exception */ - - o = exceptions_new_arraystoreexception(); - - /* remove stackframeinfo */ - - stacktrace_remove_stackframeinfo(&sfi); - - return o; -} - - -/* stacktrace_inline_classcastexception **************************************** - - Creates an ClassCastException for inline stub. - -*******************************************************************************/ - -java_objectheader *stacktrace_inline_classcastexception(u1 *pv, u1 *sp, u1 *ra, - u1 *xpc, - java_objectheader *o) -{ - stackframeinfo sfi; - java_objectheader *e; - - /* create stackframeinfo */ - - stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc); - - /* create exception */ - - e = exceptions_new_classcastexception(o); - - /* remove stackframeinfo */ - - stacktrace_remove_stackframeinfo(&sfi); - - return e; -} - - -/* stacktrace_inline_nullpointerexception ************************************** - - Creates an NullPointerException for inline stub. - -*******************************************************************************/ - -java_objectheader *stacktrace_inline_nullpointerexception(u1 *pv, u1 *sp, - u1 *ra, u1 *xpc) -{ - stackframeinfo sfi; - java_objectheader *o; - - /* create stackframeinfo */ - - stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc); - - /* create exception */ - - o = exceptions_new_nullpointerexception(); - - /* remove stackframeinfo */ - - stacktrace_remove_stackframeinfo(&sfi); - - return o; -} - - -/* 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; - - /* create stackframeinfo */ - - stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc); - - /* get exception */ - - o = *exceptionptr; - assert(o); - - /* clear exception */ - - *exceptionptr = NULL; + /* get current stackframe info pointer */ - /* resolve methodinfo pointer from exception object */ + psfi = &STACKFRAMEINFO; -#if defined(ENABLE_JAVASE) - m = class_resolvemethod(o->vftbl->class, - utf_fillInStackTrace, - utf_void__java_lang_Throwable); -#elif defined(ENABLE_JAVAME_CLDC1_1) - m = class_resolvemethod(o->vftbl->class, - utf_fillInStackTrace, - utf_void__void); -#else -#error IMPLEMENT ME! +#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 - /* call function */ - - (void) vm_call_method(m, o); - - /* remove stackframeinfo */ - - stacktrace_remove_stackframeinfo(&sfi); - - return o; -} - - -/* 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 = exceptions_new_arithmeticexception(); - - /* remove stackframeinfo */ - - stacktrace_remove_stackframeinfo(&sfi); - - return o; -} - - -/* stacktrace_hardware_nullpointerexception ************************************ - - Creates an NullPointerException for the SIGSEGV signal handler. - -*******************************************************************************/ - -java_objectheader *stacktrace_hardware_nullpointerexception(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 = exceptions_new_nullpointerexception(); - - /* remove stackframeinfo */ - - stacktrace_remove_stackframeinfo(&sfi); + /* restore the old pointer */ - return o; + *psfi = sfi->prev; } -/* 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 */ @@ -621,342 +290,331 @@ 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; - /* find the realization of the method the pc is in */ + /* Get values from the stackframeinfo. */ - code = *((codeinfo **) (pv + CodeinfoPointer)); + code = sfi->code; + pv = sfi->pv; + xpc = sfi->xpc; - /* search the line number table */ + m = code->m; - linenumber = dseg_get_linenumber_from_pc(&m, pv, pc); + /* Skip builtin methods. */ - /* now add a new entry to the staktrace */ + if (m->flags & ACC_METHOD_BUILTIN) + return stb; - stacktrace_add_entry(stb, m, linenumber); + /* Search the line number table. */ - return true; + linenumber = linenumbertable_linenumber_for_pc(&m, code, xpc); + + /* Add a new entry to the staktrace. */ + + stb = stacktrace_entry_add(stb, m, linenumber); + + return stb; } -/* stacktrace_create *********************************************************** +/* stacktrace_stack_walk ******************************************************* - Generates a stacktrace from the thread passed into a - stacktracebuffer. The stacktracebuffer is allocated on the GC - heap. + Walk the stack (or the stackframeinfo-chain) to the next method. - RETURN VALUE: - pointer to the stacktracebuffer, or - NULL if an exception has been thrown + IN: + tmpsfi ... stackframeinfo of current method + + RETURN: + true .... the sfi is filled with the new values + false ... we reached the top of the stacktrace *******************************************************************************/ -stacktracebuffer *stacktrace_create(threadobject* thread) +static inline bool stacktrace_stack_walk(stackframeinfo_t *tmpsfi) { - stacktracebuffer *stb; - stackframeinfo *sfi; - methodinfo *m; codeinfo *code; - u1 *pv; - u1 *sp; - u4 framesize; - u1 *ra; - u1 *xpc; - - /* prevent compiler warnings */ + void *pv; + void *sp; + void *ra; + void *xpc; + uint32_t framesize; + stackframeinfo_t *prevsfi; - pv = NULL; - sp = NULL; - ra = NULL; + /* Get values from the stackframeinfo. */ - /* create a stacktracebuffer in dump memory */ + code = tmpsfi->code; + pv = tmpsfi->pv; + sp = tmpsfi->sp; + ra = tmpsfi->ra; + xpc = tmpsfi->xpc; - stb = DNEW(stacktracebuffer); - - stb->capacity = STACKTRACE_CAPACITY_DEFAULT; - stb->used = 0; - stb->entries = DMNEW(stacktrace_entry, STACKTRACE_CAPACITY_DEFAULT); + /* Get the current stack frame size. */ - /* The first element in the stackframe chain must always be a - native stackframeinfo (VMThrowable.fillInStackTrace is a native - function). */ + framesize = *((uint32_t *) (((intptr_t) pv) + FrameSize)); - /* We don't use the STACKFRAMEINFO macro here, as we have to use - the passed thread. */ + /* 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_THREADS) - sfi = thread->_stackframeinfo; +#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 - sfi = _no_threads_stackframeinfo; + ra = intrp_md_stacktrace_get_returnaddress(sp, framesize); #endif -#define PRINTMETHODS 0 + /* Get the PV for the parent Java method. */ -#if PRINTMETHODS - printf("\n\nfillInStackTrace start:\n"); - fflush(stdout); +#if defined(ENABLE_INTRP) + if (opt_intrp) + pv = codegen_get_pv_from_pc(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 + } - /* Loop while we have a method pointer (asm_calljavafunction has - NULL) or there is a stackframeinfo in the chain. */ - - m = NULL; - - 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. */ - - if (m == NULL) { - /* for native stub stackframe infos, pv is always NULL */ - - if (sfi->pv == NULL) { - /* get methodinfo, sp and ra from the current stackframe info */ - - m = sfi->method; - sp = sfi->sp; /* sp of parent Java function */ - ra = sfi->ra; + /* Get the codeinfo pointer for the parent Java method. */ - if (m) - stacktrace_add_entry(stb, m, 0); + code = code_get_codeinfo_for_pv(pv); -#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*). */ + /* Calculate the SP for the parent Java method. */ #if defined(ENABLE_INTRP) - if (opt_intrp) - pv = codegen_get_pv_from_pc(ra); - else + if (opt_intrp) + sp = *(u1 **) (sp - framesize); + else #endif - { -#if defined(ENABLE_JIT) - pv = md_codegen_get_pv_from_pc(ra); + { +#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 - } - - /* get methodinfo pointer from parent data segment */ - - code = *((codeinfo **) (pv + CodeinfoPointer)); + } - /* For asm_vm_call_method the codeinfo pointer is - NULL. */ + /* 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 = (code == NULL) ? NULL : code->m; + if (code == NULL) { + prevsfi = tmpsfi->prev; - } 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 previous stackframeinfo in the chain is NULL we + reached the top of the stacktrace and return false. */ - /* get methodinfo, sp and ra from the current stackframe info */ + if (prevsfi == NULL) + return false; - 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 */ + /* Fill the temporary stackframeinfo with the new values. */ -#if PRINTMETHODS - printf("ra=%p sp=%p, ", ra, sp); - printf("NULL: inline stub\n"); - fflush(stdout); -#endif + tmpsfi->code = prevsfi->code; + tmpsfi->pv = prevsfi->pv; + tmpsfi->sp = prevsfi->sp; + tmpsfi->ra = prevsfi->ra; + tmpsfi->xpc = prevsfi->xpc; - /* get methodinfo from current Java method */ + /* Set the previous stackframe info of the temporary one to + the next in the chain. */ - code = *((codeinfo **) (pv + CodeinfoPointer)); + tmpsfi->prev = prevsfi->prev; + } + 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. */ + return true; +} - m = (code == NULL) ? NULL : code->m; - /* if m == NULL, this is a asm_calljavafunction call */ +/* stacktrace_create *********************************************************** - if (m != NULL) { -#if PRINTMETHODS - printf("ra=%p sp=%p, ", ra, sp); - method_print(m); - printf(": inline stub parent"); - fflush(stdout); -#endif + 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_INTRP) - if (!opt_intrp) { -#endif + RETURN VALUE: + pointer to the stacktracebuffer, or + NULL if there is no stacktrace available for the + given thread. - /* add the method to the stacktrace */ +*******************************************************************************/ - stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) xpc)); +stacktracebuffer *stacktrace_create(stackframeinfo_t *sfi) +{ + stacktracebuffer *stb; + stackframeinfo_t tmpsfi; + bool skip_fillInStackTrace; + bool skip_init; - /* get the current stack frame size */ + skip_fillInStackTrace = true; + skip_init = true; - framesize = *((u4 *) (pv + FrameSize)); + /* Create a stacktracebuffer in dump memory. */ -#if PRINTMETHODS - printf(", framesize=%d\n", framesize); - fflush(stdout); -#endif + stb = DNEW(stacktracebuffer); - /* Set stack pointer to stackframe of parent Java - function of the current Java function. */ + stb->capacity = STACKTRACE_CAPACITY_DEFAULT; + stb->used = 0; -#if defined(__I386__) || defined (__X86_64__) - sp += framesize + SIZEOF_VOID_P; -#elif defined(__SPARC_64__) - sp = md_get_framepointer(sp); -#else - sp += framesize; +#if !defined(NDEBUG) + if (opt_DebugStackTrace) { + printf("\n\n---> stacktrace creation start (fillInStackTrace):\n"); + fflush(stdout); + } #endif - /* get data segment and methodinfo pointer from - parent method */ - -#if defined(ENABLE_JIT) - pv = md_codegen_get_pv_from_pc(ra); -#endif + /* Put the data from the stackframeinfo into a temporary one. */ - code = *((codeinfo **) (pv + CodeinfoPointer)); + /* XXX This is not correct, but a workaround for threads-dump for + now. */ +/* assert(sfi != NULL); */ + if (sfi == NULL) + return NULL; - /* For asm_vm_call_method the codeinfo pointer is - NULL. */ + tmpsfi.code = sfi->code; + tmpsfi.pv = sfi->pv; + tmpsfi.sp = sfi->sp; + tmpsfi.ra = sfi->ra; + tmpsfi.xpc = sfi->xpc; - m = (code == NULL) ? NULL : code->m; + /* Initially set the previous stackframe info of the temporary one + to the next in the chain. */ -#if defined(ENABLE_INTRP) - } -#endif - } -#if PRINTMETHODS - else { - printf("ra=%p sp=%p, ", ra, sp); - printf("asm_calljavafunction\n"); - fflush(stdout); - } -#endif - } + tmpsfi.prev = sfi->prev; - /* get previous stackframeinfo in the chain */ + /* Iterate till we're done. */ - sfi = sfi->prev; + do { +#if !defined(NDEBUG) + /* Print current method information. */ - } else { -#if PRINTMETHODS - printf("ra=%p sp=%p, ", ra, sp); - method_print(m); - printf(": JIT"); - fflush(stdout); + 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 - /* 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); + /* This logic is taken from + hotspot/src/share/vm/classfile/javaClasses.cpp + (java_lang_Throwable::fill_in_stack_trace). */ - /* get the current stack frame size */ + if (skip_fillInStackTrace == true) { + /* Check "fillInStackTrace" only once, so we negate the + flag after the first time check. */ - framesize = *((u4 *) (pv + FrameSize)); +#if defined(WITH_CLASSPATH_GNU) + /* For GNU Classpath we also need to skip + VMThrowable.fillInStackTrace(). */ -#if PRINTMETHODS - printf(", framesize=%d\n", framesize); - fflush(stdout); + if ((tmpsfi.code->m->class == class_java_lang_VMThrowable) && + (tmpsfi.code->m->name == utf_fillInStackTrace)) + continue; #endif - /* get return address of current stack frame */ + skip_fillInStackTrace = false; -#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 (tmpsfi.code->m->name == utf_fillInStackTrace) + continue; + } - /* get data segment and methodinfo pointer from parent method */ + /* 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. */ -#if defined(ENABLE_INTRP) - if (opt_intrp) - pv = codegen_get_pv_from_pc(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 - } - - code = *((codeinfo **) (pv + CodeinfoPointer)); + 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. */ - /* For asm_vm_call_method the codeinfo pointer is NULL. */ + skip_init = false; + } + } - m = (code == NULL) ? NULL : code->m; + /* Add this method to the stacktrace. */ - /* walk the stack */ + stb = stacktrace_method_add(stb, &tmpsfi); + } while (stacktrace_stack_walk(&tmpsfi) == true); -#if defined(ENABLE_INTRP) - if (opt_intrp) - sp = *(u1 **) (sp - framesize); - else -#endif - { -#if defined(__I386__) || defined (__X86_64__) - sp += framesize + SIZEOF_VOID_P; -#elif defined(__SPARC_64__) - /* already has the new sp */ -#else - sp += framesize; -#endif - } - } +#if !defined(NDEBUG) + if (opt_DebugStackTrace) { + printf("---> stacktrace creation finished.\n\n"); + fflush(stdout); } +#endif /* return the stacktracebuffer */ - return stb; + if (stb->used == 0) + return NULL; + else + return stb; } @@ -967,12 +625,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 */ @@ -981,26 +639,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 */ @@ -1008,7 +663,7 @@ stacktracecontainer *stacktrace_fillInStackTrace(void) CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace, stacktrace_overhead) - return gcstc; + return ba; return_NULL: dump_release(dumpsize); @@ -1030,14 +685,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 */ @@ -1046,8 +701,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 */ @@ -1077,7 +733,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 */ @@ -1130,8 +786,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 @@ -1178,17 +835,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 */ @@ -1197,7 +854,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; @@ -1225,22 +882,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 */ @@ -1302,39 +959,6 @@ 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 ****************************************************** Print the stacktrace of a given exception. More or less a wrapper @@ -1342,14 +966,14 @@ void stacktrace_dump_trace(threadobject *thread) *******************************************************************************/ -void stacktrace_print_trace(java_objectheader *xptr) +void stacktrace_print_trace(java_handle_t *xptr) { - 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; @@ -1359,14 +983,17 @@ 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); }