Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
- $Id: stacktrace.c 7356 2007-02-14 11:00:28Z twisti $
-
*/
#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"
/* 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 ********************************************
-
- 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 */
-
- 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_stackframeinfo_add ***********************************************
-
-/* 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__)
- bool isleafmethod;
+ stackframeinfo_t **psfi;
+ codeinfo *code;
+#if !defined(__I386__) && !defined(__X86_64__) && !defined(__S390__) && !defined(__M68K__)
+ bool isleafmethod;
#endif
#if defined(ENABLE_JIT)
- s4 framesize;
+ 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). */
}
}
+ /* 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. */
# 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;
+ /* 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. */
- /* get current stackframe info pointer */
-
- psfi = STACKFRAMEINFO;
-
- /* restore the old pointer */
-
- *psfi = sfi->prev;
-}
-
-
-/* stacktrace_inline_arithmeticexception ***************************************
-
- Creates an ArithemticException for inline stub.
-
-*******************************************************************************/
-
-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);
-
- /* create exception */
+ stackframeinfo_t **psfi;
- o = exceptions_new_arrayindexoutofboundsexception(index);
+ /* clear the native world flag for the current thread */
+ /* ATTENTION: Clear this flag _before_ removing the stackframe info */
- /* 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.
-
-*******************************************************************************/
+ THREAD_NATIVEWORLD_EXIT;
-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 */
/* 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;
- linenumber = dseg_get_linenumber_from_pc(&m, pv, pc);
+ /* Search the line number table. */
- /* now add a new entry to the staktrace */
+ linenumber = dseg_get_linenumber_from_pc(&m, pv, xpc);
- stacktrace_add_entry(stb, m, linenumber);
+ /* Add a new entry to the staktrace. */
- return true;
+ 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:
+ sfi....stackframeinfo of current method
*******************************************************************************/
-stacktracebuffer *stacktrace_create(threadobject* thread)
+static inline void stacktrace_stack_walk(stackframeinfo_t *sfi)
{
- stacktracebuffer *stb;
- stackframeinfo *sfi;
- methodinfo *m;
- codeinfo *code;
- u1 *pv;
- u1 *sp;
- u4 framesize;
- u1 *ra;
- u1 *xpc;
-
- /* prevent compiler warnings */
+ codeinfo *code;
+ void *pv;
+ void *sp;
+ void *ra;
+ void *xpc;
+ uint32_t framesize;
- pv = NULL;
- sp = NULL;
- ra = NULL;
+ /* Get values from the stackframeinfo. */
- /* create a stacktracebuffer in dump memory */
+ code = sfi->code;
+ pv = sfi->pv;
+ sp = sfi->sp;
+ ra = sfi->ra;
+ xpc = sfi->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;
-#endif
-
-#define PRINTMETHODS 0
-
-#if PRINTMETHODS
- printf("\n\nfillInStackTrace start:\n");
- fflush(stdout);
+ ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
#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;
-
- if (m)
- stacktrace_add_entry(stb, m, 0);
-
-#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*). */
+ /* 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);
-#endif
- }
-
- /* get methodinfo pointer from parent data segment */
-
- code = *((codeinfo **) (pv + CodeinfoPointer));
-
- /* For asm_vm_call_method the codeinfo pointer is
- NULL. */
-
- m = (code == NULL) ? NULL : code->m;
-
- } 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!!! */
-
- /* get methodinfo, sp and ra from the current stackframe info */
-
- 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 PRINTMETHODS
- printf("ra=%p sp=%p, ", ra, sp);
- printf("NULL: inline stub\n");
- fflush(stdout);
+# 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 from current Java method */
-
- code = *((codeinfo **) (pv + CodeinfoPointer));
-
- /* For asm_vm_call_method the codeinfo pointer is
- NULL. */
+ /* Get the codeinfo pointer for the parent Java method. */
- m = (code == NULL) ? NULL : code->m;
+ code = code_get_codeinfo_for_pv(pv);
- /* if m == NULL, this is a asm_calljavafunction call */
-
- if (m != NULL) {
-#if PRINTMETHODS
- printf("ra=%p sp=%p, ", ra, sp);
- method_print(m);
- printf(": inline stub parent");
- fflush(stdout);
-#endif
+ /* Calculate the SP for the parent Java method. */
#if defined(ENABLE_INTRP)
- if (!opt_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
+ }
- /* add the method to the stacktrace */
-
- stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) xpc));
+ /* 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. */
- /* get the current stack frame size */
+ sfi->code = code;
+ sfi->pv = pv;
+ sfi->sp = sp;
+ sfi->ra = ra;
+ sfi->xpc = (void *) (((intptr_t) ra) - 1);
+}
- framesize = *((u4 *) (pv + FrameSize));
-#if PRINTMETHODS
- printf(", framesize=%d\n", framesize);
- fflush(stdout);
-#endif
+/* stacktrace_create ***********************************************************
- /* Set stack pointer to stackframe of parent Java
- function of the current Java function. */
+ 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(__I386__) || defined (__X86_64__)
- sp += framesize + SIZEOF_VOID_P;
-#elif defined(__SPARC_64__)
- sp = md_get_framepointer(sp);
-#else
- sp += framesize;
-#endif
+ RETURN VALUE:
+ pointer to the stacktracebuffer, or
+ NULL if there is no stacktrace available for the
+ given thread.
- /* get data segment and methodinfo pointer from
- parent method */
+*******************************************************************************/
-#if defined(ENABLE_JIT)
- pv = md_codegen_get_pv_from_pc(ra);
-#endif
+stacktracebuffer *stacktrace_create(stackframeinfo_t *sfi)
+{
+ stacktracebuffer *stb;
+ stackframeinfo_t tmpsfi;
- code = *((codeinfo **) (pv + CodeinfoPointer));
+ /* Create a stacktracebuffer in dump memory. */
- /* For asm_vm_call_method the codeinfo pointer is
- NULL. */
+ stb = DNEW(stacktracebuffer);
- m = (code == NULL) ? NULL : code->m;
+ stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
+ stb->used = 0;
-#if defined(ENABLE_INTRP)
- }
-#endif
- }
-#if PRINTMETHODS
- else {
- printf("ra=%p sp=%p, ", ra, sp);
- printf("asm_calljavafunction\n");
- fflush(stdout);
- }
+#if !defined(NDEBUG)
+ if (opt_DebugStackTrace) {
+ printf("\n\n---> stacktrace creation start (fillInStackTrace):\n");
+ fflush(stdout);
+ }
#endif
- }
- /* get previous stackframeinfo in the chain */
+ /* Put the data from the stackframeinfo into a temporary one. */
- sfi = sfi->prev;
+ /* XXX This is not correct, but a workaround for threads-dump for
+ now. */
+/* assert(sfi != NULL); */
+ if (sfi == NULL)
+ return NULL;
- } else {
-#if PRINTMETHODS
- printf("ra=%p sp=%p, ", ra, sp);
- method_print(m);
- printf(": JIT");
- fflush(stdout);
-#endif
+ tmpsfi.code = sfi->code;
+ tmpsfi.pv = sfi->pv;
+ tmpsfi.sp = sfi->sp;
+ tmpsfi.ra = sfi->ra;
+ tmpsfi.xpc = sfi->xpc;
- /* JIT method found, add it to the stacktrace (we subtract
- 1 from the return address since it points the the
- instruction after call). */
+ /* Iterate till we're done. */
- stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1);
+ for (;;) {
+#if !defined(NDEBUG)
+ /* Print current method information. */
- /* get the current stack frame size */
+ 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
- framesize = *((u4 *) (pv + FrameSize));
+ /* Check for Throwable.fillInStackTrace(). */
-#if PRINTMETHODS
- printf(", framesize=%d\n", framesize);
- fflush(stdout);
-#endif
+/* if (tmpsfi.method->name != utf_fillInStackTrace) { */
+
+ /* Add this method to the stacktrace. */
- /* get return address of current stack frame */
+ stb = stacktrace_method_add(stb, &tmpsfi);
+/* } */
-#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
+ /* Walk the stack (or the stackframeinfo chain) and get the
+ next method. */
- /* get data segment and methodinfo pointer from parent method */
+ stacktrace_stack_walk(&tmpsfi);
-#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
- }
+ /* 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. */
- code = *((codeinfo **) (pv + CodeinfoPointer));
+ if (tmpsfi.code == NULL) {
+ sfi = sfi->prev;
- /* For asm_vm_call_method the codeinfo pointer is NULL. */
+ /* If the previous stackframeinfo in the chain is NULL we
+ reached the top of the stacktrace and leave the
+ loop. */
- m = (code == NULL) ? NULL : code->m;
+ if (sfi == NULL)
+ break;
- /* walk the stack */
+ /* Fill the temporary stackframeinfo with the new
+ values. */
-#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
- }
+ tmpsfi.code = sfi->code;
+ tmpsfi.pv = sfi->pv;
+ tmpsfi.sp = sfi->sp;
+ tmpsfi.ra = sfi->ra;
+ tmpsfi.xpc = sfi->xpc;
}
}
+#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;
}
*******************************************************************************/
-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 */
/* 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 */
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 */
/* 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 */
continue;
}
- oa->data[i] = (java_objectheader *) ste->method->class;
+ LLNI_array_direct(oa, i) = (java_object_t *) ste->method->class;
}
/* release dump memory */
/* 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
*******************************************************************************/
#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 */
/* create a stacktrace for the current thread */
- stb = stacktrace_create(THREADOBJECT);
+ stb = stacktrace_create(STACKFRAMEINFO);
if (stb == NULL)
goto return_NULL;
/* 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_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<<No stacktrace available>>");
- fflush(stdout);
- }
-
- dump_release(dumpsize);
-}
-
-
/* stacktrace_print_trace ******************************************************
Print the stacktrace of a given exception. More or less a wrapper
*******************************************************************************/
-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;
/* 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);
}