/* 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.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
- $Id: stacktrace.c 7343 2007-02-13 02:36:29Z ajordan $
-
*/
#include "config.h"
#include <assert.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "vm/types.h"
+#include "md.h"
+
#include "mm/gc-common.h"
#include "mm/memory.h"
#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
#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;
-#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 */
-
- 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);
-
- }
+stackframeinfo_t *_no_threads_stackframeinfo = NULL;
#endif
- /* fill new stackframe info structure */
+CYCLES_STATS_DECLARE(stacktrace_overhead , 100, 1)
+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 = 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;
-#endif
+ stackframeinfo_t **psfi;
+ codeinfo *code;
#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. */
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. */
-
- isleafmethod = *((s4 *) (pv + IsLeaf));
+ /* 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. */
- if (!isleafmethod) {
+ if ((code == NULL) || !code_is_leafmethod(code)) {
framesize = *((u4 *) (pv + FrameSize));
ra = md_stacktrace_get_returnaddress(sp, framesize);
# if defined(ENABLE_INTRP)
}
# endif
-#endif /* defined(ENABLE_JIT) */
-
- /* fill new stackframe info structure */
-
- sfi->prev = *psfi;
- sfi->method = NULL;
- sfi->pv = pv;
- sfi->sp = sp;
- sfi->ra = ra;
- sfi->xpc = xpc;
-
- /* store new stackframe info pointer */
-
- *psfi = sfi;
-}
-
-
-/* stacktrace_create_native_stackframeinfo *************************************
-
- Creates a stackframe info structure for a native stub.
-
-*******************************************************************************/
-
-void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv,
- u1 *sp, u1 *ra)
-{
- stackframeinfo **psfi;
- methodinfo *m;
- codeinfo *code;
-
- /* get codeinfo pointer from data segment */
-
- code = *((codeinfo **) (pv + CodeinfoPointer));
-
- /* For asm_vm_call_method the codeinfo pointer is NULL. */
-
- m = (code == NULL) ? NULL : code->m;
-
- /* get current stackframe info pointer */
+#endif
- psfi = STACKFRAMEINFO;
+ /* Calculate XPC when not given. The XPC is then the return
+ address of the current method minus 1 because the RA points to
+ the instruction after the call instruction. This is required
+ e.g. for method stubs. */
- /* fill new stackframe info structure */
+ if (xpc == NULL) {
+ xpc = (void *) (((intptr_t) ra) - 1);
+ }
- sfi->prev = *psfi;
- sfi->method = m;
- sfi->pv = NULL;
- sfi->sp = sp;
- sfi->ra = ra;
- sfi->xpc = NULL;
+ /* Fill new stackframeinfo structure. */
+
+ sfi->prev = *psfi;
+ sfi->code = code;
+ sfi->pv = pv;
+ sfi->sp = sp;
+ sfi->ra = ra;
+ sfi->xpc = xpc;
+
+#if !defined(NDEBUG)
+ if (opt_DebugStackFrameInfo) {
+ log_start();
+ log_print("[stackframeinfo add : sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
+ sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
+ method_print(sfi->code->m);
+ log_print("]");
+ log_finish();
+ }
+#endif
- /* store new stackframe info pointer */
+ /* Store new stackframeinfo pointer. */
*psfi = sfi;
-}
-
-
-/* stacktrace_remove_stackframeinfo ********************************************
-
- Remove the topmost stackframeinfo in the current thread.
-
-*******************************************************************************/
-
-void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
-{
- stackframeinfo **psfi;
-
- /* get current stackframe info pointer */
-
- psfi = STACKFRAMEINFO;
- /* restore the old pointer */
-
- *psfi = sfi->prev;
-}
-
-
-/* stacktrace_inline_arithmeticexception ***************************************
-
- Creates an ArithemticException for inline stub.
-
-*******************************************************************************/
-
-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);
+ /* 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. */
- /* 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;
+ stackframeinfo_t **psfi;
- /* create stackframeinfo */
+ /* clear the native world flag for the current thread */
+ /* ATTENTION: Clear this flag _before_ removing the stackframe info */
- stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
+ THREAD_NATIVEWORLD_EXIT;
- /* create exception */
+ /* get current stackframe info pointer */
- o = exceptions_new_arrayindexoutofboundsexception(index);
+ psfi = &STACKFRAMEINFO;
- /* remove 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
- stacktrace_remove_stackframeinfo(&sfi);
+ /* restore the old pointer */
- return o;
+ *psfi = sfi->prev;
}
-/* stacktrace_inline_arraystoreexception ***************************************
-
- Creates an ArrayStoreException for inline stub.
+/* stacktrace_stackframeinfo_fill **********************************************
-*******************************************************************************/
-
-java_objectheader *stacktrace_inline_arraystoreexception(u1 *pv, u1 *sp, u1 *ra,
- u1 *xpc)
-{
- stackframeinfo sfi;
- java_objectheader *o;
+ Fill the temporary stackframeinfo structure with the values given
+ in sfi.
- /* 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.
+ IN:
+ tmpsfi ... temporary stackframeinfo
+ sfi ...... stackframeinfo to be used in the next iteration
*******************************************************************************/
-java_objectheader *stacktrace_inline_classcastexception(u1 *pv, u1 *sp, u1 *ra,
- u1 *xpc,
- java_objectheader *o)
+static inline void stacktrace_stackframeinfo_fill(stackframeinfo_t *tmpsfi, stackframeinfo_t *sfi)
{
- stackframeinfo sfi;
- java_objectheader *e;
+ /* Sanity checks. */
- /* create stackframeinfo */
+ assert(tmpsfi != NULL);
+ assert(sfi != NULL);
- stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
+ /* Fill the temporary stackframeinfo. */
- /* create exception */
+ tmpsfi->code = sfi->code;
+ tmpsfi->pv = sfi->pv;
+ tmpsfi->sp = sfi->sp;
+ tmpsfi->ra = sfi->ra;
+ tmpsfi->xpc = sfi->xpc;
- e = exceptions_new_classcastexception(o);
+ /* Set the previous stackframe info of the temporary one to the
+ next in the chain. */
- /* remove stackframeinfo */
+ tmpsfi->prev = sfi->prev;
- stacktrace_remove_stackframeinfo(&sfi);
+#if !defined(NDEBUG)
+ /* Print current method information. */
- return e;
+ if (opt_DebugStackTrace) {
+ log_println("[stacktrace start]");
+ 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_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_stackframeinfo_next **********************************************
+ Walk the stack (or the stackframeinfo-chain) to the next method and
+ return the new stackframe values in the temporary stackframeinfo
+ passed.
-/* stacktrace_inline_fillInStackTrace ******************************************
+ ATTENTION: This function does NOT skip builtin methods!
- Fills in the correct stacktrace into an existing exception object
- (this one is for inline exception stubs).
+ IN:
+ tmpsfi ... temporary stackframeinfo of current method
*******************************************************************************/
-java_objectheader *stacktrace_inline_fillInStackTrace(u1 *pv, u1 *sp, u1 *ra,
- u1 *xpc)
+static inline void stacktrace_stackframeinfo_next(stackframeinfo_t *tmpsfi)
{
- stackframeinfo sfi;
- java_objectheader *o;
- methodinfo *m;
-
- /* create stackframeinfo */
+ codeinfo *code;
+ void *pv;
+ void *sp;
+ void *ra;
+ void *xpc;
+ uint32_t framesize;
+ stackframeinfo_t *prevsfi;
- stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
+ /* Sanity check. */
- /* get exception */
+ assert(tmpsfi != NULL);
- o = *exceptionptr;
- assert(o);
+ /* Get values from the stackframeinfo. */
- /* clear exception */
+ code = tmpsfi->code;
+ pv = tmpsfi->pv;
+ sp = tmpsfi->sp;
+ ra = tmpsfi->ra;
+ xpc = tmpsfi->xpc;
+
+ /* Get the current stack frame size. */
- *exceptionptr = NULL;
+ framesize = *((uint32_t *) (((intptr_t) pv) + FrameSize));
- /* resolve methodinfo pointer from exception object */
+ /* 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_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);
+#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
-#error IMPLEMENT ME!
+ ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
#endif
- /* call function */
-
- (void) vm_call_method(m, o);
-
- /* remove stackframeinfo */
-
- stacktrace_remove_stackframeinfo(&sfi);
-
- return o;
-}
+ /* Get the PV for the parent Java method. */
+#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
+ }
-/* stacktrace_hardware_arithmeticexception *************************************
+ /* Get the codeinfo pointer for the parent Java method. */
- Creates an ArithemticException for inline stub.
+ code = code_get_codeinfo_for_pv(pv);
-*******************************************************************************/
+ /* Calculate the SP for the parent Java method. */
-java_objectheader *stacktrace_hardware_arithmeticexception(u1 *pv, u1 *sp,
- u1 *ra, u1 *xpc)
-{
- stackframeinfo sfi;
- java_objectheader *o;
+#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
+ }
- /* create stackframeinfo */
+ /* 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. */
- stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
+ if (code == NULL) {
+ prevsfi = tmpsfi->prev;
- /* create exception */
+ /* 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. */
- o = exceptions_new_arithmeticexception();
+ if (prevsfi == NULL) {
+ tmpsfi->code = NULL;
+ tmpsfi->prev = NULL;
+ return;
+ }
- /* remove stackframeinfo */
+ /* Fill the temporary stackframeinfo with the new values. */
- stacktrace_remove_stackframeinfo(&sfi);
+ 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);
+ }
- return o;
+#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_hardware_nullpointerexception ************************************
-
- Creates an NullPointerException for the SIGSEGV signal handler.
+/* stacktrace_stackframeinfo_end_check *****************************************
-*******************************************************************************/
+ Check if we reached the end of the stacktrace.
-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);
-
- return o;
-}
-
-
-/* stacktrace_add_entry ********************************************************
+ IN:
+ tmpsfi ... temporary stackframeinfo of current method
- Adds a new entry to the stacktrace buffer.
+ RETURN:
+ true .... the end is reached
+ false ... the end is not reached
*******************************************************************************/
-static void stacktrace_add_entry(stacktracebuffer *stb, methodinfo *m, u2 line)
+static inline bool stacktrace_stackframeinfo_end_check(stackframeinfo_t *tmpsfi)
{
- stacktrace_entry *ste;
+ /* Sanity check. */
- /* check if we already reached the buffer capacity */
+ assert(tmpsfi != NULL);
- if (stb->used >= stb->capacity) {
- /* reallocate new memory */
-
- stb->entries = DMREALLOC(stb->entries, stacktrace_entry, stb->capacity,
- stb->capacity + STACKTRACE_CAPACITY_INCREMENT);
-
- /* set new buffer capacity */
+ if ((tmpsfi->code == NULL) && (tmpsfi->prev == NULL)) {
+#if !defined(NDEBUG)
+ if (opt_DebugStackTrace)
+ log_println("[stacktrace stop]");
+#endif
- stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
+ return true;
}
- /* insert the current entry */
-
- ste = &(stb->entries[stb->used]);
-
- ste->method = m;
- ste->linenumber = line;
-
- /* increase entries used count */
-
- stb->used += 1;
+ return false;
}
-/* stacktrace_add_method *******************************************************
+/* stacktrace_depth ************************************************************
- Add stacktrace entries[1] for the given method to the stacktrace buffer.
+ Calculates and returns the depth of the current 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
-
- 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)
-
-*******************************************************************************/
-
-static bool stacktrace_add_method(stacktracebuffer *stb, methodinfo *m, u1 *pv,
- u1 *pc)
-{
- codeinfo *code; /* compiled realization of method */
- s4 linenumber;
+ sfi ... stackframeinfo where to start the stacktrace
- /* find the realization of the method the pc is in */
-
- code = *((codeinfo **) (pv + CodeinfoPointer));
-
- /* search the line number table */
-
- linenumber = dseg_get_linenumber_from_pc(&m, pv, pc);
-
- /* now add a new entry to the staktrace */
-
- stacktrace_add_entry(stb, m, linenumber);
-
- return true;
-}
-
-
-/* stacktrace_create ***********************************************************
-
- Generates a stacktrace from the thread passed into a
- stacktracebuffer. The stacktracebuffer is allocated on the GC
- heap.
-
- RETURN VALUE:
- pointer to the stacktracebuffer, or
- NULL if an exception has been thrown
+ RETURN:
+ depth of the stacktrace
*******************************************************************************/
-stacktracebuffer *stacktrace_create(threadobject* thread)
+static int stacktrace_depth(stackframeinfo_t *sfi)
{
- stacktracebuffer *stb;
- stackframeinfo *sfi;
+ stackframeinfo_t tmpsfi;
+ int depth;
methodinfo *m;
- codeinfo *code;
- u1 *pv;
- u1 *sp;
- u4 framesize;
- u1 *ra;
- u1 *xpc;
- /* prevent compiler warnings */
+#if !defined(NDEBUG)
+ if (opt_DebugStackTrace)
+ log_println("[stacktrace_depth]");
+#endif
- pv = NULL;
- sp = NULL;
- ra = NULL;
+ /* XXX This is not correct, but a workaround for threads-dump for
+ now. */
+/* assert(sfi != NULL); */
+ if (sfi == NULL)
+ return 0;
- /* create a stacktracebuffer in dump memory */
+ /* Iterate over all stackframes. */
- stb = DNEW(stacktracebuffer);
+ depth = 0;
- stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
- stb->used = 0;
- stb->entries = DMNEW(stacktrace_entry, STACKTRACE_CAPACITY_DEFAULT);
+ for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
+ stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
+ stacktrace_stackframeinfo_next(&tmpsfi)) {
+ /* Get methodinfo. */
- /* The first element in the stackframe chain must always be a
- native stackframeinfo (VMThrowable.fillInStackTrace is a native
- function). */
+ m = tmpsfi.code->m;
- /* We don't use the STACKFRAMEINFO macro here, as we have to use
- the passed thread. */
+ /* Skip builtin methods. */
-#if defined(ENABLE_THREADS)
- sfi = thread->_stackframeinfo;
-#else
- sfi = _no_threads_stackframeinfo;
-#endif
-
-#define PRINTMETHODS 0
+ if (m->flags & ACC_METHOD_BUILTIN)
+ continue;
-#if PRINTMETHODS
- printf("\n\nfillInStackTrace start:\n");
- fflush(stdout);
-#endif
+ depth++;
+ }
- /* Loop while we have a method pointer (asm_calljavafunction has
- NULL) or there is a stackframeinfo in the chain. */
+ return depth;
+}
- 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. */
+/* stacktrace_get **************************************************************
- if (m == NULL) {
- /* for native stub stackframe infos, pv is always NULL */
+ Builds and returns a stacktrace from the current thread for and
+ returns the stacktrace structure wrapped in a Java byte-array to
+ not confuse the GC.
- if (sfi->pv == NULL) {
- /* get methodinfo, sp and ra from the current stackframe info */
+ RETURN:
+ stacktrace as Java byte-array
- m = sfi->method;
- sp = sfi->sp; /* sp of parent Java function */
- ra = sfi->ra;
+*******************************************************************************/
- if (m)
- stacktrace_add_entry(stb, m, 0);
+java_handle_bytearray_t *stacktrace_get(void)
+{
+ 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;
-#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*). */
+ CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
-#if defined(ENABLE_INTRP)
- if (opt_intrp)
- pv = codegen_get_pv_from_pc(ra);
- else
+#if !defined(NDEBUG)
+ if (opt_DebugStackTrace)
+ log_println("[stacktrace_get]");
#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));
+ skip_fillInStackTrace = true;
+ skip_init = true;
- /* For asm_vm_call_method the codeinfo pointer is
- NULL. */
+ /* Get the stacktrace depth of the current thread. */
- m = (code == NULL) ? NULL : code->m;
+ sfi = STACKFRAMEINFO;
- } 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!!! */
+ depth = stacktrace_depth(sfi);
- /* get methodinfo, sp and ra from the current stackframe info */
+ if (depth == 0)
+ return NULL;
- 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 */
+ /* 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. */
-#if PRINTMETHODS
- printf("ra=%p sp=%p, ", ra, sp);
- printf("NULL: inline stub\n");
- fflush(stdout);
-#endif
-
- /* 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__)
- 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->class == 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 <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. */
-#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) {
+/* throwable->is_a(method->method_holder())) { */
+ continue;
}
+ else {
+ /* If no "Throwable.init()" method found, we stop
+ checking it next time. */
- /* get previous stackframeinfo in the chain */
-
- sfi = sfi->prev;
-
- } else {
-#if PRINTMETHODS
- printf("ra=%p sp=%p, ", ra, sp);
- method_print(m);
- printf(": JIT");
- fflush(stdout);
-#endif
-
- /* JIT method found, add it to the stacktrace (we subtract
- 1 from the return address since it points the the
- instruction after call). */
-
- stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1);
-
- /* get the current stack frame size */
-
- framesize = *((u4 *) (pv + FrameSize));
+ skip_init = false;
+ }
+ }
-#if PRINTMETHODS
- printf(", framesize=%d\n", framesize);
- fflush(stdout);
-#endif
+ /* Store the stacktrace entry and increment the pointer. */
- /* get return address of current stack frame */
+ ste->code = tmpsfi.code;
+ ste->pc = tmpsfi.xpc;
-#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
+ ste++;
+ }
- /* get data segment and methodinfo pointer from parent method */
+ /* Store the number of entries in the stacktrace structure. */
-#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
- }
+ st->length = ste - st->entries;
- code = *((codeinfo **) (pv + CodeinfoPointer));
+ LLNI_CRITICAL_END;
- /* For asm_vm_call_method the codeinfo pointer is NULL. */
+ /* release dump memory */
- m = (code == NULL) ? NULL : code->m;
+/* dump_release(dumpsize); */
- /* walk the stack */
+ CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
+ stacktrace_overhead)
+ return ba;
-#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
- }
- }
- }
+return_NULL:
+/* dump_release(dumpsize); */
- /* return the stacktracebuffer */
+ CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
+ stacktrace_overhead)
- return stb;
+ return NULL;
}
-/* stacktrace_fillInStackTrace *************************************************
+/* stacktrace_first_nonnull_classloader ****************************************
+
+ Returns the first non-null (user-defined) classloader on the stack.
+ If none is found NULL is returned.
- Generate a stacktrace from the current thread for
- java.lang.VMThrowable.fillInStackTrace.
+ RETURN:
+ classloader
*******************************************************************************/
-stacktracecontainer *stacktrace_fillInStackTrace(void)
+classloader *stacktrace_first_nonnull_classloader(void)
{
- stacktracebuffer *stb;
- stacktracecontainer *gcstc;
- s4 gcstc_size;
- s4 dumpsize;
- CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
-
- /* mark start of dump memory area */
-
- dumpsize = dump_size();
-
- /* create a stacktrace from the current thread */
-
- stb = stacktrace_create(THREADOBJECT);
- if (!stb)
- 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 */
-
- gcstc_size = sizeof(stacktracebuffer) +
- sizeof(stacktrace_entry) * stb->used;
- gcstc = (stacktracecontainer *) builtin_newarray_byte(gcstc_size);
-
- if (gcstc == NULL)
- goto return_NULL;
+ stackframeinfo_t *sfi;
+ stackframeinfo_t tmpsfi;
+ methodinfo *m;
+ classloader *cl;
- gcstc->stb.capacity = stb->capacity;
- gcstc->stb.used = stb->used;
- gcstc->stb.entries = gcstc->data;
+#if !defined(NDEBUG)
+ if (opt_DebugStackTrace)
+ log_println("[stacktrace_first_nonnull_classloader]");
+#endif
- MCOPY(gcstc->data, stb->entries, stacktrace_entry, stb->used);
+ /* Get the stackframeinfo of the current thread. */
- /* release dump memory */
+ sfi = STACKFRAMEINFO;
- dump_release(dumpsize);
+ /* Iterate over the whole stack. */
- CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
- stacktrace_overhead)
- return gcstc;
+ for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
+ stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
+ stacktrace_stackframeinfo_next(&tmpsfi)) {
-return_NULL:
- dump_release(dumpsize);
+ m = tmpsfi.code->m;
+ cl = class_get_classloader(m->class);
- CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
- stacktrace_overhead)
+ if (cl != NULL)
+ return cl;
+ }
return NULL;
}
*******************************************************************************/
-java_objectarray *stacktrace_getClassContext(void)
+java_handle_objectarray_t *stacktrace_getClassContext(void)
{
- stacktracebuffer *stb;
- stacktrace_entry *ste;
- java_objectarray *oa;
- s4 oalength;
- s4 i;
- s4 dumpsize;
+ 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 = STACKFRAMEINFO;
- /* create a stacktrace for the current thread */
+ /* Get the depth of the current stack. */
- stb = stacktrace_create(THREADOBJECT);
- if (!stb)
- goto return_NULL;
+ depth = stacktrace_depth(sfi);
- /* calculate the size of the Class array */
+ /* The first stackframe corresponds to the method whose
+ implementation calls this native function. We remove that
+ entry. */
- for (i = 0, oalength = 0; i < stb->used; i++)
- if (stb->entries[i].method != NULL)
- oalength++;
+ depth--;
+ stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
+ stacktrace_stackframeinfo_next(&tmpsfi);
- /* The first entry corresponds to the method whose implementation */
- /* calls stacktrace_getClassContext. We remove that entry. */
+ /* Allocate the Class array. */
- ste = &(stb->entries[0]);
- ste++;
- oalength--;
+ oa = builtin_anewarray(depth, class_java_lang_Class);
- /* allocate the Class array */
+ if (oa == NULL) {
+ CYCLES_STATS_END(stacktrace_getClassContext);
- oa = builtin_anewarray(oalength, class_java_lang_Class);
- if (!oa)
- goto return_NULL;
+ return NULL;
+ }
- /* fill the Class array from the stacktracebuffer */
+ /* Fill the Class array from the stacktrace list. */
- for(i = 0; i < oalength; i++, ste++) {
- if (ste->method == NULL) {
- i--;
- continue;
- }
+ LLNI_CRITICAL_START;
- oa->data[i] = (java_objectheader *) ste->method->class;
- }
+ data = LLNI_array_data(oa);
- /* release dump memory */
+ /* Iterate over the whole stack. */
- dump_release(dumpsize);
+ i = 0;
- CYCLES_STATS_END(stacktrace_getClassContext)
+ for (;
+ stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
+ stacktrace_stackframeinfo_next(&tmpsfi)) {
+ /* Get methodinfo. */
- return oa;
+ m = tmpsfi.code->m;
-return_NULL:
- dump_release(dumpsize);
+ /* Skip builtin methods. */
+
+ if (m->flags & ACC_METHOD_BUILTIN)
+ continue;
+
+ /* Store the class in the array. */
+
+ data[i] = (java_object_t *) m->class;
+
+ i++;
+ }
+
+ LLNI_CRITICAL_END;
CYCLES_STATS_END(stacktrace_getClassContext)
- return NULL;
+ return oa;
}
*******************************************************************************/
#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(THREADOBJECT);
- if (!stb)
- goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
+ sfi = STACKFRAMEINFO;
- /* iterate over all stacktrace entries and find the first suitable
- class */
+ /* If the stackframeinfo is NULL then FindClass is called through
+ the Invocation Interface and we return NULL */
- for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
- m = ste->method;
+ if (sfi == NULL) {
+ CYCLES_STATS_END(stacktrace_getCurrentClass);
- if (m == NULL)
- continue;
+ return NULL;
+ }
- if (m->class == class_java_security_PrivilegedAction)
- goto return_NULL;
+ /* Iterate over the whole stack. */
- if (m->class != NULL) {
- dump_release(dumpsize);
+ for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
+ stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
+ stacktrace_stackframeinfo_next(&tmpsfi)) {
+ /* Get the methodinfo. */
+
+ m = tmpsfi.code->m;
- CYCLES_STATS_END(stacktrace_getCurrentClass)
+ if (m->class == class_java_security_PrivilegedAction) {
+ CYCLES_STATS_END(stacktrace_getCurrentClass);
+
+ return NULL;
+ }
+
+ if (m->class != NULL) {
+ CYCLES_STATS_END(stacktrace_getCurrentClass);
return m->class;
}
}
- /* no Java method found on the stack */
-
-return_NULL:
- dump_release(dumpsize);
+ /* 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_objectarray *stacktrace_getStack(void)
+#if defined(ENABLE_JAVASE) && defined(WITH_CLASSPATH_GNU)
+java_handle_objectarray_t *stacktrace_get_stack(void)
{
- stacktracebuffer *stb;
- stacktrace_entry *ste;
- java_objectarray *oa;
- java_objectarray *classes;
- java_objectarray *methodnames;
- classinfo *c;
- java_objectheader *string;
- s4 i;
- s4 dumpsize;
- CYCLES_STATS_DECLARE_AND_START
+ stackframeinfo_t *sfi;
+ stackframeinfo_t tmpsfi;
+ int depth;
+ java_handle_objectarray_t *oa;
+ java_handle_objectarray_t *classes;
+ java_handle_objectarray_t *methodnames;
+ methodinfo *m;
+ java_handle_t *string;
+ 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(THREADOBJECT);
+ sfi = 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. */
+
+ array_objectarray_element_set(oa, 0, (java_handle_t *) classes);
+ array_objectarray_element_set(oa, 1, (java_handle_t *) methodnames);
- oa->data[0] = (java_objectheader *) classes;
- oa->data[1] = (java_objectheader *) methodnames;
+ /* Iterate over the whole stack. */
+ /* TODO We should use a critical section here to speed things
+ up. */
- /* iterate over all stacktrace entries */
+ i = 0;
- for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
- c = ste->method->class;
+ for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
+ stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
+ stacktrace_stackframeinfo_next(&tmpsfi)) {
+ /* Get the methodinfo. */
- classes->data[i] = (java_objectheader *) c;
+ m = tmpsfi.code->m;
+
+ /* Skip builtin methods. */
+
+ if (m->flags & ACC_METHOD_BUILTIN)
+ continue;
- string = javastring_new(ste->method->name);
+ /* 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->class;
+
+ /* 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_trace_from_buffer ******************************************
+/* stacktrace_print ************************************************************
- 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.
+ 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_trace_from_buffer(stacktracebuffer *stb)
+void stacktrace_print(stacktrace_t *st)
{
- stacktrace_entry *ste;
- methodinfo *m;
- s4 i;
+ stacktrace_entry_t *ste;
+ methodinfo *m;
+ int32_t linenumber;
+ int i;
+
+ ste = &(st->entries[0]);
- ste = &(stb->entries[0]);
+ for (i = 0; i < st->length; i++, ste++) {
+ m = ste->code->m;
- for (i = 0; i < stb->used; i++, ste++) {
- m = ste->method;
+ /* Get the line number. */
+
+ linenumber = linenumbertable_linenumber_for_pc(&m, ste->code, ste->pc);
printf("\tat ");
utf_display_printable_ascii_classname(m->class->name);
if (m->flags & ACC_NATIVE) {
puts("(Native Method)");
-
- } else {
+ }
+ else {
printf("(");
utf_display_printable_ascii(m->class->sourcefile);
- printf(":%d)\n", (u4) ste->linenumber);
+ printf(":%d)\n", linenumber);
}
}
}
-/* stacktrace_dump_trace *******************************************************
+/* stacktrace_print_exception **************************************************
+
+ Print the stacktrace of a given exception (more or less a wrapper
+ to stacktrace_print).
- This method is call from signal_handler_sigusr1 to dump the
- stacktrace of the current thread to stdout.
+ IN:
+ h ... handle of exception to print
*******************************************************************************/
-void stacktrace_dump_trace(threadobject *thread)
+void stacktrace_print_exception(java_handle_t *h)
{
- stacktracebuffer *stb;
- s4 dumpsize;
+ java_lang_Throwable *o;
- /* mark start of dump memory area */
+#if defined(WITH_CLASSPATH_GNU)
+ java_lang_VMThrowable *vmt;
+ gnu_classpath_Pointer *backtrace;
+#elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
+ java_lang_Object *backtrace;
+#endif
- dumpsize = dump_size();
+ java_handle_bytearray_t *ba;
+ stacktrace_t *st;
- /* create a stacktrace for the current thread */
+ o = (java_lang_Throwable *) h;
- stb = stacktrace_create(thread);
+ if (o == NULL)
+ return;
- /* print stacktrace */
+ /* now print the stacktrace */
- if (stb != NULL)
- stacktrace_print_trace_from_buffer(stb);
- else {
- puts("\t<<No stacktrace available>>");
- fflush(stdout);
- }
+#if defined(WITH_CLASSPATH_GNU)
- dump_release(dumpsize);
-}
+ LLNI_field_get_ref(o, vmState, vmt);
+ LLNI_field_get_ref(vmt, vmData, backtrace);
+#elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
-/* stacktrace_print_trace ******************************************************
+ LLNI_field_get_ref(o, backtrace, backtrace);
- Print the stacktrace of a given exception. More or less a wrapper
- to stacktrace_print_trace_from_buffer.
+#else
+# error unknown classpath configuration
+#endif
-*******************************************************************************/
+ ba = (java_handle_bytearray_t *) backtrace;
-void stacktrace_print_trace(java_objectheader *xptr)
-{
- java_lang_Throwable *t;
-#if defined(WITH_CLASSPATH_GNU)
- java_lang_VMThrowable *vmt;
-#endif
- stacktracecontainer *stc;
- stacktracebuffer *stb;
+ /* Sanity check. */
- t = (java_lang_Throwable *) xptr;
+ assert(ba != NULL);
- if (t == NULL)
- return;
+ /* We need a critical section here as we use the byte-array data
+ pointer directly. */
- /* now print the stacktrace */
+ LLNI_CRITICAL_START;
+
+ st = (stacktrace_t *) LLNI_array_data(ba);
-#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);
-#endif
+ 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