Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
- $Id: stacktrace.c 7792 2007-04-22 20:02:05Z tbfg $
-
*/
#include "config.h"
#include <assert.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#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)
#include "toolbox/logging.h"
+#include "vm/array.h"
#include "vm/builtin.h"
#include "vm/cycles-stats.h"
#include "vm/exceptions.h"
#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"
/* 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)
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 */
}
}
+ /* 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 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. */
# 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);
+ }
- /* store new stackframe info pointer */
+ /* 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 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;
+ stackframeinfo_t **psfi;
- /* get codeinfo pointer from data segment */
+ /* clear the native world flag for the current thread */
+ /* ATTENTION: Clear this flag _before_ removing the stackframe info */
- code = *((codeinfo **) (pv + CodeinfoPointer));
-
- /* 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 */
}
-/* 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 */
/* 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.
-
- NOTE: The first element in the stackframe chain must always be a
- native stackframeinfo (e.g. VMThrowable.fillInStackTrace() is
- a native function).
+ 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(stackframeinfo *sfi)
+static inline void stacktrace_stackframeinfo_fill(stackframeinfo_t *tmpsfi, stackframeinfo_t *sfi)
{
- stacktracebuffer *stb;
- 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;
+}
-#define PRINTMETHODS 0
-#if PRINTMETHODS
- printf("\n\nfillInStackTrace start:\n");
- fflush(stdout);
-#endif
+/* stacktrace_stackframeinfo_next **********************************************
- /* Loop while we have a method pointer (asm_calljavafunction has
- NULL) or there is a stackframeinfo in the chain. */
+ Walk the stack (or the stackframeinfo-chain) to the next method and
+ return the new stackframe values in the temporary stackframeinfo
+ passed.
- m = NULL;
+ IN:
+ tmpsfi ... temporary stackframeinfo of current method
- 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 */
+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;
- if (sfi->pv == NULL) {
- /* get methodinfo, sp and ra from the current stackframe info */
+ /* Sanity check. */
- m = sfi->method;
- sp = sfi->sp; /* sp of parent Java function */
- ra = sfi->ra;
+ assert(tmpsfi != NULL);
- if (m)
- stacktrace_add_entry(stb, m, 0);
+ /* Get values from the stackframeinfo. */
-#if PRINTMETHODS
- printf("ra=%p sp=%p, ", ra, sp);
- method_print(m);
- printf(": native stub\n");
- fflush(stdout);
+ 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));
+
+ /* 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__) || defined (__M68K__)
- 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). */
+ /* Put the data from the stackframeinfo into a temporary one. */
- stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1);
-
- /* get the current stack frame size */
-
- 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 <init> methods of the exceptions klass. If there is
+ <init> 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 */
if (stb->used == 0)
*******************************************************************************/
-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 */
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 */
CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
stacktrace_overhead)
- return gcstc;
+ return ba;
return_NULL:
dump_release(dumpsize);
*******************************************************************************/
-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 */
continue;
}
- oa->data[i] = (java_objectheader *) ste->method->class;
+ LLNI_array_direct(oa, i) = (java_object_t *) ste->method->class;
}
/* release dump memory */
*******************************************************************************/
#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 */
/* 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 */
}
-/* 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;
/* 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);
}