X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fvm%2Fjit%2Fstacktrace.c;h=461c09d18f68d38ff92196ac1ad0f2daf64febab;hb=8c81647e1c96715f45498a3ada7f795b5c9dfe81;hp=2eaa5089a449428b6a7177e873d2f5a5b114751f;hpb=d70e11353693c830f485424adde3ceff0ed30327;p=cacao.git diff --git a/src/vm/jit/stacktrace.c b/src/vm/jit/stacktrace.c index 2eaa5089a..461c09d18 100644 --- a/src/vm/jit/stacktrace.c +++ b/src/vm/jit/stacktrace.c @@ -1,9 +1,7 @@ /* src/vm/jit/stacktrace.c - machine independent stacktrace system - Copyright (C) 1996-2005, 2006, 2007 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,19 +20,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - $Id: stacktrace.c 8318 2007-08-16 10:05:34Z michi $ - */ #include "config.h" #include +#include #include #include #include "vm/types.h" +#include "md.h" + #include "mm/gc-common.h" #include "mm/memory.h" @@ -43,20 +42,20 @@ #include "vm/global.h" /* required here for native includes */ #include "native/jni.h" #include "native/llni.h" + +#include "native/include/java_lang_Object.h" #include "native/include/java_lang_Throwable.h" #if defined(WITH_CLASSPATH_GNU) +# include "native/include/gnu_classpath_Pointer.h" # include "native/include/java_lang_VMThrowable.h" #endif -#if defined(ENABLE_THREADS) -# include "threads/native/threads.h" -#else -# include "threads/none/threads.h" -#endif +#include "threads/thread.h" #include "toolbox/logging.h" +#include "vm/array.h" #include "vm/builtin.h" #include "vm/cycles-stats.h" #include "vm/exceptions.h" @@ -65,107 +64,44 @@ #include "vm/jit/asmpart.h" #include "vm/jit/codegen-common.h" +#include "vm/jit/linenumbertable.h" #include "vm/jit/methodheader.h" +#include "vm/jit/methodtree.h" #include "vmcore/class.h" #include "vmcore/loader.h" +#include "vmcore/method.h" #include "vmcore/options.h" /* global variables ***********************************************************/ -#if !defined(ENABLE_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) - - -/* stacktrace_create_stackframeinfo ******************************************** - - Creates an stackframe info structure for inline code in the - interpreter. - -*******************************************************************************/ - -#if defined(ENABLE_INTRP) -void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv, u1 *sp, - u1 *ra) -{ - 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 -#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 */ +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) - 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 */ +/* stacktrace_stackframeinfo_add *********************************************** - 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). + Fills a stackframe info structure with the given or calculated + values and adds it to the chain. *******************************************************************************/ -void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv, - u1 *sp, u1 *ra, u1 *xpc) +void stacktrace_stackframeinfo_add(stackframeinfo_t *sfi, u1 *pv, u1 *sp, u1 *ra, u1 *xpc) { - stackframeinfo **psfi; -#if !defined(__I386__) && !defined(__X86_64__) && !defined(__S390__) && !defined(__M68K__) - bool isleafmethod; -#endif + stackframeinfo_t *currentsfi; + codeinfo *code; #if defined(ENABLE_JIT) - s4 framesize; + s4 framesize; #endif - /* get current stackframe info pointer */ + /* Get current stackframe info. */ - 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). */ @@ -173,7 +109,7 @@ void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv, if (pv == NULL) { #if defined(ENABLE_INTRP) if (opt_intrp) - pv = codegen_get_pv_from_pc(ra); + pv = methodtree_find(ra); else #endif { @@ -187,6 +123,13 @@ 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. */ @@ -204,14 +147,13 @@ void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv, 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. */ + /* 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. */ - isleafmethod = *((s4 *) (pv + IsLeaf)); - - if (!isleafmethod) { + if ((code == NULL) || !code_is_leafmethod(code)) { framesize = *((u4 *) (pv + FrameSize)); ra = md_stacktrace_get_returnaddress(sp, framesize); @@ -220,505 +162,638 @@ void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv, # if defined(ENABLE_INTRP) } # endif -#endif /* defined(ENABLE_JIT) */ +#endif + + /* 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); + } + + /* 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 - /* fill new stackframe info structure */ + /* Store new stackframeinfo pointer. */ - sfi->prev = *psfi; - sfi->method = NULL; - sfi->pv = pv; - sfi->sp = sp; - sfi->ra = ra; - sfi->xpc = xpc; + threads_set_current_stackframeinfo(sfi); - /* store new stackframe info 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; + 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; + /* 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 - /* get codeinfo pointer from data segment */ + /* Set previous stackframe info. */ - code = *((codeinfo **) (pv + CodeinfoPointer)); + threads_set_current_stackframeinfo(sfi->prev); +} - /* For asm_vm_call_method the codeinfo pointer is NULL. */ - m = (code == NULL) ? NULL : code->m; +/* stacktrace_stackframeinfo_fill ********************************************** - /* get current stackframe info pointer */ + Fill the temporary stackframeinfo structure with the values given + in sfi. - psfi = &STACKFRAMEINFO; + IN: + tmpsfi ... temporary stackframeinfo + sfi ...... stackframeinfo to be used in the next iteration - /* fill new stackframe info structure */ +*******************************************************************************/ + +static inline void stacktrace_stackframeinfo_fill(stackframeinfo_t *tmpsfi, stackframeinfo_t *sfi) +{ + /* Sanity checks. */ + + assert(tmpsfi != NULL); + assert(sfi != NULL); + + /* Fill the temporary stackframeinfo. */ + + tmpsfi->code = sfi->code; + tmpsfi->pv = sfi->pv; + tmpsfi->sp = sfi->sp; + tmpsfi->ra = sfi->ra; + tmpsfi->xpc = sfi->xpc; - sfi->prev = *psfi; - sfi->method = m; - sfi->pv = NULL; - sfi->sp = sp; - sfi->ra = ra; - sfi->xpc = NULL; + /* Set the previous stackframe info of the temporary one to the + next in the chain. */ - /* store new stackframe info pointer */ + tmpsfi->prev = sfi->prev; - *psfi = sfi; +#if !defined(NDEBUG) + if (opt_DebugStackTrace) + log_println("[stacktrace fill]"); +#endif } -/* stacktrace_remove_stackframeinfo ******************************************** +/* stacktrace_stackframeinfo_next ********************************************** + + Walk the stack (or the stackframeinfo-chain) to the next method and + return the new stackframe values in the temporary stackframeinfo + passed. - Remove the topmost stackframeinfo in the current thread. + ATTENTION: This function does NOT skip builtin methods! + + IN: + tmpsfi ... temporary stackframeinfo of current method *******************************************************************************/ -void stacktrace_remove_stackframeinfo(stackframeinfo *sfi) +static inline void stacktrace_stackframeinfo_next(stackframeinfo_t *tmpsfi) { - stackframeinfo **psfi; + codeinfo *code; + void *pv; + void *sp; + void *ra; + void *xpc; + uint32_t framesize; + stackframeinfo_t *prevsfi; - /* get current stackframe info pointer */ + /* Sanity check. */ - psfi = &STACKFRAMEINFO; + assert(tmpsfi != NULL); - /* restore the old pointer */ + /* Get values from the stackframeinfo. */ - *psfi = sfi->prev; -} + code = tmpsfi->code; + pv = tmpsfi->pv; + sp = tmpsfi->sp; + ra = tmpsfi->ra; + xpc = tmpsfi->xpc; + + /* Get the current stack frame size. */ + framesize = *((uint32_t *) (((intptr_t) pv) + FrameSize)); -/* stacktrace_add_entry ******************************************************** + /* 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). */ - Adds a new entry to the stacktrace buffer. +#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 -*******************************************************************************/ + /* Get the PV for the parent Java method. */ -static void stacktrace_add_entry(stacktracebuffer *stb, methodinfo *m, u2 line) -{ - stacktrace_entry *ste; +#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 the codeinfo pointer for the parent Java method. */ - /* check if we already reached the buffer capacity */ + code = code_get_codeinfo_for_pv(pv); - if (stb->used >= stb->capacity) { - /* reallocate new memory */ + /* Calculate the SP for the parent Java method. */ - stb->entries = DMREALLOC(stb->entries, stacktrace_entry, stb->capacity, - stb->capacity + STACKTRACE_CAPACITY_INCREMENT); +#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 + } - /* set new buffer capacity */ + /* 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. */ - stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT; - } + if (code == NULL) { + prevsfi = tmpsfi->prev; - /* insert the current entry */ + /* 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. */ - ste = &(stb->entries[stb->used]); + if (prevsfi == NULL) { + tmpsfi->code = NULL; + tmpsfi->prev = NULL; + return; + } - ste->method = m; - ste->linenumber = line; + /* Fill the temporary stackframeinfo with the new values. */ - /* increase entries used count */ + 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); + } - stb->used += 1; +#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_add_method ******************************************************* +/* stacktrace_stackframeinfo_end_check ***************************************** - Add stacktrace entries[1] for the given method to the stacktrace buffer. + Check if we reached the end of the stacktrace. 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 + tmpsfi ... temporary stackframeinfo of current method - OUT: - true, if stacktrace entries were successfully created, false otherwise. - - [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: + true .... the end is reached + false ... the end is not reached *******************************************************************************/ -static bool stacktrace_add_method(stacktracebuffer *stb, methodinfo *m, u1 *pv, - u1 *pc) +static inline bool stacktrace_stackframeinfo_end_check(stackframeinfo_t *tmpsfi) { - codeinfo *code; /* compiled realization of method */ - s4 linenumber; - - /* find the realization of the method the pc is in */ - - code = *((codeinfo **) (pv + CodeinfoPointer)); + /* Sanity check. */ - /* search the line number table */ + assert(tmpsfi != NULL); - linenumber = dseg_get_linenumber_from_pc(&m, pv, pc); - - /* now add a new entry to the staktrace */ + if ((tmpsfi->code == NULL) && (tmpsfi->prev == NULL)) { +#if !defined(NDEBUG) + if (opt_DebugStackTrace) + log_println("[stacktrace stop]"); +#endif - stacktrace_add_entry(stb, m, linenumber); + return true; + } - return true; + return false; } -/* stacktrace_create *********************************************************** +/* stacktrace_depth ************************************************************ - 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). + Calculates and returns the depth of the current stacktrace. - RETURN VALUE: - pointer to the stacktracebuffer, or - NULL if there is no stacktrace available for the - given thread. + IN: + sfi ... stackframeinfo where to start the stacktrace + + RETURN: + depth of the stacktrace *******************************************************************************/ -stacktracebuffer *stacktrace_create(stackframeinfo *sfi) +static int stacktrace_depth(stackframeinfo_t *sfi) { - stacktracebuffer *stb; + stackframeinfo_t tmpsfi; + int depth; methodinfo *m; - codeinfo *code; - u1 *pv; - u1 *sp; - u4 framesize; - u1 *ra; - u1 *xpc; - - /* prevent compiler warnings */ - pv = NULL; - sp = NULL; - ra = NULL; +#if !defined(NDEBUG) + if (opt_DebugStackTrace) + log_println("[stacktrace_depth]"); +#endif - /* create a stacktracebuffer in dump memory */ + /* XXX This is not correct, but a workaround for threads-dump for + now. */ +/* assert(sfi != NULL); */ + if (sfi == NULL) + return 0; - stb = DNEW(stacktracebuffer); + /* Iterate over all stackframes. */ - stb->capacity = STACKTRACE_CAPACITY_DEFAULT; - stb->used = 0; - stb->entries = DMNEW(stacktrace_entry, STACKTRACE_CAPACITY_DEFAULT); + depth = 0; -#define PRINTMETHODS 0 + for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi); + stacktrace_stackframeinfo_end_check(&tmpsfi) == false; + stacktrace_stackframeinfo_next(&tmpsfi)) { + /* Get methodinfo. */ -#if PRINTMETHODS - printf("\n\nfillInStackTrace start:\n"); - fflush(stdout); -#endif + m = tmpsfi.code->m; - /* Loop while we have a method pointer (asm_calljavafunction has - NULL) or there is a stackframeinfo in the chain. */ + /* Skip builtin methods. */ - m = NULL; + if (m->flags & ACC_METHOD_BUILTIN) + continue; - 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. */ + depth++; + } - if (m == NULL) { - /* for native stub stackframe infos, pv is always NULL */ + return depth; +} - 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; +/* stacktrace_get ************************************************************** - if (m) - stacktrace_add_entry(stb, m, 0); + 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. -#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*). */ + IN: + sfi ... stackframe info to start stacktrace from -#if defined(ENABLE_INTRP) - if (opt_intrp) - pv = codegen_get_pv_from_pc(ra); - else -#endif - { -#if defined(ENABLE_JIT) - pv = md_codegen_get_pv_from_pc(ra); -#endif - } + RETURN: + stacktrace as Java byte-array - /* get methodinfo pointer from parent data segment */ +*******************************************************************************/ - code = *((codeinfo **) (pv + CodeinfoPointer)); +java_handle_bytearray_t *stacktrace_get(stackframeinfo_t *sfi) +{ + 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; - /* For asm_vm_call_method the codeinfo pointer is - NULL. */ + CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD - m = (code == NULL) ? NULL : code->m; +#if !defined(NDEBUG) + if (opt_DebugStackTrace) + log_println("[stacktrace_get]"); +#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!!! */ + skip_fillInStackTrace = true; + skip_init = true; - /* get methodinfo, sp and ra from the current stackframe info */ + depth = stacktrace_depth(sfi); - 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 (depth == 0) + return NULL; -#if PRINTMETHODS - printf("ra=%p sp=%p, ", ra, sp); - printf("NULL: inline stub\n"); - fflush(stdout); -#endif + /* 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. */ - /* get methodinfo from current Java method */ + ba_size = sizeof(stacktrace_t) + sizeof(stacktrace_entry_t) * depth; - code = *((codeinfo **) (pv + CodeinfoPointer)); + ba = builtin_newarray_byte(ba_size); - /* For asm_vm_call_method the codeinfo pointer is - NULL. */ + if (ba == NULL) + goto return_NULL; - m = (code == NULL) ? NULL : code->m; + /* Get a stacktrace entry pointer. */ + /* ATTENTION: We need a critical section here because we use the + byte-array data pointer directly. */ - /* if m == NULL, this is a asm_calljavafunction call */ + LLNI_CRITICAL_START; - if (m != NULL) { -#if PRINTMETHODS - printf("ra=%p sp=%p, ", ra, sp); - method_print(m); - printf(": inline stub parent"); - fflush(stdout); -#endif + st = (stacktrace_t *) LLNI_array_data(ba); -#if defined(ENABLE_INTRP) - if (!opt_intrp) { -#endif + ste = st->entries; - /* add the method to the stacktrace */ + /* Iterate over the whole stack. */ - stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) xpc)); + for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi); + stacktrace_stackframeinfo_end_check(&tmpsfi) == false; + stacktrace_stackframeinfo_next(&tmpsfi)) { + /* Get the methodinfo. */ - /* get the current stack frame size */ + m = tmpsfi.code->m; - framesize = *((u4 *) (pv + FrameSize)); + /* Skip builtin methods. */ -#if PRINTMETHODS - printf(", framesize=%d\n", framesize); - fflush(stdout); -#endif + if (m->flags & ACC_METHOD_BUILTIN) + continue; - /* Set stack pointer to stackframe of parent Java - function of the current Java function. */ + /* This logic is taken from + hotspot/src/share/vm/classfile/javaClasses.cpp + (java_lang_Throwable::fill_in_stack_trace). */ -#if defined(__I386__) || defined (__X86_64__) || defined (__M68K__) - sp += framesize + SIZEOF_VOID_P; -#elif defined(__SPARC_64__) - sp = md_get_framepointer(sp); -#else - 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_JIT) - pv = md_codegen_get_pv_from_pc(ra); + if ((m->clazz == class_java_lang_VMThrowable) && + (m->name == utf_fillInStackTrace)) + continue; #endif - code = *((codeinfo **) (pv + CodeinfoPointer)); + skip_fillInStackTrace = false; - /* For asm_vm_call_method the codeinfo pointer is - NULL. */ + if (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. */ -#if defined(ENABLE_INTRP) - } -#endif - } -#if PRINTMETHODS - else { - printf("ra=%p sp=%p, ", ra, sp); - printf("asm_calljavafunction\n"); - fflush(stdout); - } -#endif + 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. */ - /* get previous stackframeinfo in the chain */ + skip_init = false; + } + } - sfi = sfi->prev; + /* Store the stacktrace entry and increment the pointer. */ - } else { -#if PRINTMETHODS - printf("ra=%p sp=%p, ", ra, sp); - method_print(m); - printf(": JIT"); - fflush(stdout); -#endif + ste->code = tmpsfi.code; + ste->pc = tmpsfi.xpc; - /* JIT method found, add it to the stacktrace (we subtract - 1 from the return address since it points the the - instruction after call). */ + ste++; + } - stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1); + /* Store the number of entries in the stacktrace structure. */ - /* get the current stack frame size */ + st->length = ste - st->entries; - framesize = *((u4 *) (pv + FrameSize)); + LLNI_CRITICAL_END; -#if PRINTMETHODS - printf(", framesize=%d\n", framesize); - fflush(stdout); -#endif + /* release dump memory */ - /* get return address of current stack frame */ +/* dump_release(dumpsize); */ -#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 + CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace, + stacktrace_overhead) + return ba; - /* get data segment and methodinfo pointer from parent method */ +return_NULL: +/* dump_release(dumpsize); */ -#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 - } + CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace, + stacktrace_overhead) - code = *((codeinfo **) (pv + CodeinfoPointer)); + return NULL; +} - /* For asm_vm_call_method the codeinfo pointer is NULL. */ - m = (code == NULL) ? NULL : code->m; +/* stacktrace_get_current ****************************************************** - /* walk the stack */ + 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 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 - } - } - } + RETURN: + stacktrace as Java byte-array - /* return the stacktracebuffer */ +*******************************************************************************/ - if (stb->used == 0) - return NULL; - else - return stb; +java_handle_bytearray_t *stacktrace_get_current(void) +{ + stackframeinfo_t *sfi; + java_handle_bytearray_t *ba; + + sfi = threads_get_current_stackframeinfo(); + ba = stacktrace_get(sfi); + + return ba; } -/* stacktrace_fillInStackTrace ************************************************* +/* stacktrace_get_caller_class ************************************************* - Generate a stacktrace from the current thread for - java.lang.VMThrowable.fillInStackTrace. + Get the class on the stack at the given depth. This function skips + various special classes or methods. + + ARGUMENTS: + depth ... depth to get caller class of + + RETURN: + caller class *******************************************************************************/ -stacktracecontainer *stacktrace_fillInStackTrace(void) +#if defined(ENABLE_JAVASE) +classinfo *stacktrace_get_caller_class(int depth) { - stacktracebuffer *stb; - stacktracecontainer *gcstc; - s4 gcstc_size; - s4 dumpsize; - CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD + stackframeinfo_t *sfi; + stackframeinfo_t tmpsfi; + methodinfo *m; + classinfo *c; + int i; - /* mark start of dump memory area */ +#if !defined(NDEBUG) + if (opt_DebugStackTrace) + log_println("[stacktrace_get_caller_class]"); +#endif - dumpsize = dump_size(); + /* Get the stackframeinfo of the current thread. */ - /* create a stacktrace from the current thread */ + sfi = threads_get_current_stackframeinfo(); - stb = stacktrace_create(STACKFRAMEINFO); + /* Iterate over the whole stack until we reached the requested + depth. */ - if (stb == NULL) - goto return_NULL; + i = 0; - /* allocate memory from the GC heap and copy the stacktrace buffer */ - /* ATTENTION: use stacktracecontainer for this and make it look like - an array */ + for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi); + stacktrace_stackframeinfo_end_check(&tmpsfi) == false; + stacktrace_stackframeinfo_next(&tmpsfi)) { - gcstc_size = sizeof(stacktracebuffer) + - sizeof(stacktrace_entry) * stb->used; - gcstc = (stacktracecontainer *) builtin_newarray_byte(gcstc_size); + m = tmpsfi.code->m; + c = m->clazz; - if (gcstc == NULL) - goto return_NULL; + /* Skip builtin methods. */ - gcstc->stb.capacity = stb->capacity; - gcstc->stb.used = stb->used; - gcstc->stb.entries = gcstc->data; + if (m->flags & ACC_METHOD_BUILTIN) + continue; - MCOPY(gcstc->data, stb->entries, stacktrace_entry, stb->used); +#if defined(WITH_CLASSPATH_SUN) + /* NOTE: See hotspot/src/share/vm/runtime/vframe.cpp + (vframeStreamCommon::security_get_caller_frame). */ - /* release dump memory */ + /* This is java.lang.reflect.Method.invoke(), skip it. */ - dump_release(dumpsize); + if (m == method_java_lang_reflect_Method_invoke) + continue; - CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace, - stacktrace_overhead) - return gcstc; + /* This is an auxiliary frame, skip it. */ -return_NULL: - dump_release(dumpsize); + if (class_issubclass(c, class_sun_reflect_MagicAccessorImpl)) + continue; +#endif - CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace, - stacktrace_overhead) + /* We reached the requested depth. */ + + if (i >= depth) + return c; + + i++; + } + + return NULL; +} +#endif + + +/* stacktrace_first_nonnull_classloader **************************************** + + Returns the first non-null (user-defined) classloader on the stack. + If none is found NULL is returned. + + RETURN: + classloader + +*******************************************************************************/ + +classloader_t *stacktrace_first_nonnull_classloader(void) +{ + stackframeinfo_t *sfi; + stackframeinfo_t tmpsfi; + methodinfo *m; + classloader_t *cl; + +#if !defined(NDEBUG) + if (opt_DebugStackTrace) + log_println("[stacktrace_first_nonnull_classloader]"); +#endif + + /* Get the stackframeinfo of the current thread. */ + + sfi = threads_get_current_stackframeinfo(); + + /* Iterate over the whole stack. */ + + for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi); + stacktrace_stackframeinfo_end_check(&tmpsfi) == false; + stacktrace_stackframeinfo_next(&tmpsfi)) { + + m = tmpsfi.code->m; + cl = class_get_classloader(m->clazz); + + if (cl != NULL) + return cl; + } return NULL; } @@ -736,69 +811,79 @@ return_NULL: java_handle_objectarray_t *stacktrace_getClassContext(void) { - stacktracebuffer *stb; - stacktrace_entry *ste; - java_handle_objectarray_t *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(STACKFRAMEINFO); + depth = stacktrace_depth(sfi); - if (stb == NULL) - goto return_NULL; + /* The first stackframe corresponds to the method whose + implementation calls this native function. We remove that + entry. */ - /* calculate the size of the Class array */ + depth--; + stacktrace_stackframeinfo_fill(&tmpsfi, sfi); + stacktrace_stackframeinfo_next(&tmpsfi); - for (i = 0, oalength = 0; i < stb->used; i++) - if (stb->entries[i].method != NULL) - oalength++; + /* Allocate the Class array. */ - /* The first entry corresponds to the method whose implementation */ - /* calls stacktrace_getClassContext. We remove that entry. */ + oa = builtin_anewarray(depth, class_java_lang_Class); - ste = &(stb->entries[0]); - ste++; - oalength--; + if (oa == NULL) { + CYCLES_STATS_END(stacktrace_getClassContext); - /* allocate the Class array */ + return NULL; + } - oa = builtin_anewarray(oalength, class_java_lang_Class); - if (!oa) - goto return_NULL; + /* Fill the Class array from the stacktrace list. */ - /* fill the Class array from the stacktracebuffer */ + LLNI_CRITICAL_START; - for(i = 0; i < oalength; i++, ste++) { - if (ste->method == NULL) { - i--; - continue; - } + data = LLNI_array_data(oa); - oa->data[i] = (java_object_t *) ste->method->class; - } + /* Iterate over the whole stack. */ - /* release dump memory */ + i = 0; - dump_release(dumpsize); + for (; + stacktrace_stackframeinfo_end_check(&tmpsfi) == false; + stacktrace_stackframeinfo_next(&tmpsfi)) { + /* Get methodinfo. */ - CYCLES_STATS_END(stacktrace_getClassContext) + m = tmpsfi.code->m; - return oa; + /* Skip builtin methods. */ -return_NULL: - dump_release(dumpsize); + 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; } @@ -820,240 +905,410 @@ return_NULL: *******************************************************************************/ #if defined(ENABLE_JAVASE) -classinfo *stacktrace_getCurrentClass(void) +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(STACKFRAMEINFO); + sfi = threads_get_current_stackframeinfo(); - if (stb == NULL) - goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */ + /* If the stackframeinfo is NULL then FindClass is called through + the Invocation Interface and we return NULL */ - /* iterate over all stacktrace entries and find the first suitable - class */ + if (sfi == NULL) { + CYCLES_STATS_END(stacktrace_getCurrentClass); - for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) { - m = ste->method; + return NULL; + } - if (m == NULL) - continue; + /* Iterate over the whole stack. */ - if (m->class == class_java_security_PrivilegedAction) - goto return_NULL; + 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; + } + } + + /* No Java method found on the stack. */ - CYCLES_STATS_END(stacktrace_getCurrentClass) + 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 *******************************************************************************/ -#if defined(ENABLE_JAVASE) -java_handle_objectarray_t *stacktrace_getStack(void) +#if defined(ENABLE_JAVASE) && defined(WITH_CLASSPATH_GNU) +java_handle_objectarray_t *stacktrace_get_stack(void) { - stacktracebuffer *stb; - stacktrace_entry *ste; + stackframeinfo_t *sfi; + stackframeinfo_t tmpsfi; + int depth; java_handle_objectarray_t *oa; java_handle_objectarray_t *classes; java_handle_objectarray_t *methodnames; - classinfo *c; + methodinfo *m; java_handle_t *string; - s4 i; - s4 dumpsize; - CYCLES_STATS_DECLARE_AND_START + int i; - /* mark start of dump memory area */ + CYCLES_STATS_DECLARE_AND_START - dumpsize = dump_size(); +#if !defined(NDEBUG) + if (opt_DebugStackTrace) + log_println("[stacktrace_get_stack]"); +#endif - /* create a stacktrace for the current thread */ + /* Get the stackframeinfo of the current thread. */ - stb = stacktrace_create(STACKFRAMEINFO); + sfi = threads_get_current_stackframeinfo(); - if (stb == NULL) - 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 == NULL) goto return_NULL; - classes = builtin_anewarray(stb->used, class_java_lang_Class); + classes = builtin_anewarray(depth, class_java_lang_Class); 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 == NULL) goto return_NULL; - /* set up the 2-dimensional array */ + /* Set up the 2-dimensional array. */ - oa->data[0] = (java_object_t *) classes; - oa->data[1] = (java_object_t *) 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_object_t *) c; + for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi); + stacktrace_stackframeinfo_end_check(&tmpsfi) == false; + stacktrace_stackframeinfo_next(&tmpsfi)) { + /* Get the methodinfo. */ - string = javastring_new(ste->method->name); + m = tmpsfi.code->m; + + /* Skip builtin methods. */ + + if (m->flags & ACC_METHOD_BUILTIN) + continue; + + /* Store the class in the array. */ + /* NOTE: We use a LLNI-macro here, because a classinfo is not + a handle. */ + + LLNI_array_direct(classes, i) = (java_object_t *) m->clazz; + + /* Store the name in the array. */ + + string = javastring_new(m->name); if (string == NULL) goto return_NULL; - methodnames->data[i] = string; - } - - /* return the 2-dimensional array */ + array_objectarray_element_set(methodnames, i, string); - dump_release(dumpsize); + i++; + } - CYCLES_STATS_END(stacktrace_getStack) + 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 /* ENABLE_JAVASE */ +#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 *******************************************************************************/ -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_print_trace ****************************************************** +/* stacktrace_print ************************************************************ + + Print the given stacktrace with CACAO intern methods only (no Java + code required). + + This method is used by stacktrace_dump_trace and + builtin_trace_exception. + + IN: + st ... stacktrace to print + +*******************************************************************************/ + +void stacktrace_print(stacktrace_t *st) +{ + stacktrace_entry_t *ste; + methodinfo *m; + int32_t linenumber; + int i; + + ste = &(st->entries[0]); + + for (i = 0; i < st->length; i++, ste++) { + m = ste->code->m; + + /* Get the line number. */ + + linenumber = linenumbertable_linenumber_for_pc(&m, ste->code, ste->pc); + + stacktrace_print_entry(m, linenumber); + } +} + + +/* stacktrace_print_current **************************************************** + + Print the current stacktrace of the current thread. - Print the stacktrace of a given exception. More or less a wrapper - to stacktrace_print_trace_from_buffer. + NOTE: This function prints all frames of the stacktrace and does + not skip frames like stacktrace_get. *******************************************************************************/ -void stacktrace_print_trace(java_handle_t *xptr) +void stacktrace_print_current(void) { - java_lang_Throwable *t; + 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); + } +} + + +/* stacktrace_print_of_thread ************************************************** + + Print the current stacktrace of the given thread. + + ARGUMENTS: + t ... thread + +*******************************************************************************/ + +#if defined(ENABLE_THREADS) +void stacktrace_print_of_thread(threadobject *t) +{ + stackframeinfo_t *sfi; + stackframeinfo_t tmpsfi; + codeinfo *code; + methodinfo *m; + int32_t linenumber; + + /* Build a stacktrace for the passed thread. */ + + sfi = t->_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); + } +} +#endif + + +/* stacktrace_print_exception ************************************************** + + 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_exception(java_handle_t *h) +{ + java_lang_Throwable *o; + #if defined(WITH_CLASSPATH_GNU) - java_lang_VMThrowable *vmt; + java_lang_VMThrowable *vmt; #endif - stacktracecontainer *stc; - stacktracebuffer *stb; - t = (java_lang_Throwable *) xptr; + java_lang_Object *backtrace; + java_handle_bytearray_t *ba; + stacktrace_t *st; + + o = (java_lang_Throwable *) h; - if (t == NULL) + if (o == NULL) return; /* now print the stacktrace */ #if defined(WITH_CLASSPATH_GNU) - LLNI_field_get_ref(t, vmState, vmt); - stc = (stacktracecontainer *) LLNI_field_direct(vmt, vmData); + + LLNI_field_get_ref(o, vmState, vmt); + LLNI_field_get_ref(vmt, vmdata, backtrace); + #elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1) - stc = (stacktracecontainer *) t->backtrace; + + LLNI_field_get_ref(o, backtrace, backtrace); + #else # error unknown classpath configuration #endif - stb = &(stc->stb); + 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