/* 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.
#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 "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_fillInStackTrace,40,5000)
-CYCLES_STATS_DECLARE(stacktrace_getClassContext ,40,5000)
-CYCLES_STATS_DECLARE(stacktrace_getCurrentClass ,40,5000)
-CYCLES_STATS_DECLARE(stacktrace_getStack ,40,10000)
+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)
/* stacktrace_stackframeinfo_add ***********************************************
*******************************************************************************/
-void stacktrace_stackframeinfo_add(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;
- methodinfo *m;
-#if !defined(__I386__) && !defined(__X86_64__) && !defined(__S390__) && !defined(__M68K__)
- bool isleafmethod;
-#endif
+ stackframeinfo_t **psfi;
+ codeinfo *code;
#if defined(ENABLE_JIT)
- s4 framesize;
+ s4 framesize;
#endif
/* get current stackframe info pointer */
}
}
- /* Get methodinfo pointer for the parent Java method. */
+ /* Get codeinfo pointer for the parent Java method. */
- m = code_get_methodinfo_for_pv(pv);
+ code = code_get_codeinfo_for_pv(pv);
/* XXX */
/* assert(m != NULL); */
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);
/* Fill new stackframeinfo structure. */
- sfi->prev = *psfi;
- sfi->method = m;
- sfi->pv = pv;
- sfi->sp = sp;
- sfi->ra = ra;
- sfi->xpc = xpc;
+ 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->method, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
- method_print(sfi->method);
+ sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
+ method_print(sfi->code->m);
log_print("]");
log_finish();
}
*******************************************************************************/
-void stacktrace_stackframeinfo_remove(stackframeinfo *sfi)
+void stacktrace_stackframeinfo_remove(stackframeinfo_t *sfi)
{
- stackframeinfo **psfi;
+ stackframeinfo_t **psfi;
/* clear the native world flag for the current thread */
/* ATTENTION: Clear this flag _before_ removing the stackframe info */
if (opt_DebugStackFrameInfo) {
log_start();
log_print("[stackframeinfo remove: sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
- sfi, sfi->method, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
- method_print(sfi->method);
+ sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
+ method_print(sfi->code->m);
log_print("]");
log_finish();
}
}
-/* stacktrace_entry_add ********************************************************
+/* stacktrace_stackframeinfo_fill **********************************************
- Adds a new entry to the stacktrace buffer.
+ Fill the temporary stackframeinfo structure with the values given
+ in sfi.
+
+ IN:
+ tmpsfi ... temporary stackframeinfo
+ sfi ...... stackframeinfo to be used in the next iteration
*******************************************************************************/
-static inline stacktracebuffer *stacktrace_entry_add(stacktracebuffer *stb, methodinfo *m, u2 line)
+static inline void stacktrace_stackframeinfo_fill(stackframeinfo_t *tmpsfi, stackframeinfo_t *sfi)
{
- stacktrace_entry *ste;
- u4 stb_size_old;
- u4 stb_size_new;
+ /* Sanity checks. */
- /* check if we already reached the buffer capacity */
+ assert(tmpsfi != NULL);
+ assert(sfi != NULL);
- if (stb->used >= stb->capacity) {
- /* calculate size of stacktracebuffer */
+ /* Fill the temporary stackframeinfo. */
- stb_size_old = sizeof(stacktracebuffer) +
- sizeof(stacktrace_entry) * stb->capacity -
- sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_DEFAULT;
+ tmpsfi->code = sfi->code;
+ tmpsfi->pv = sfi->pv;
+ tmpsfi->sp = sfi->sp;
+ tmpsfi->ra = sfi->ra;
+ tmpsfi->xpc = sfi->xpc;
- stb_size_new = stb_size_old +
- sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_INCREMENT;
+ /* Set the previous stackframe info of the temporary one to the
+ next in the chain. */
- /* reallocate new memory */
+ tmpsfi->prev = sfi->prev;
- stb = DMREALLOC(stb, u1, stb_size_old, stb_size_new);
-
- /* set new buffer capacity */
+#if !defined(NDEBUG)
+ /* Print current method information. */
- stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
+ 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();
}
-
- /* insert the current entry */
-
- ste = &(stb->entries[stb->used]);
-
- ste->method = m;
- ste->linenumber = line;
-
- /* increase entries used count */
-
- stb->used += 1;
-
- return stb;
+#endif
}
-/* stacktrace_method_add *******************************************************
+/* stacktrace_stackframeinfo_next **********************************************
- Add stacktrace entries[1] for the given method to the stacktrace
- buffer.
+ Walk the stack (or the stackframeinfo-chain) to the next method and
+ return the new stackframe values in the temporary stackframeinfo
+ passed.
- IN:
- stb....stacktracebuffer to fill
- sfi....current stackframeinfo
- OUT:
- stacktracebuffer after possible reallocation.
+ ATTENTION: This function does NOT skip builtin methods!
- [1] In case of inlined methods there may be more than one stacktrace
- entry for a codegen-level method. (see doc/inlining_stacktrace.txt)
+ IN:
+ tmpsfi ... temporary stackframeinfo of current method
*******************************************************************************/
-static inline stacktracebuffer *stacktrace_method_add(stacktracebuffer *stb, stackframeinfo *sfi)
+static inline void stacktrace_stackframeinfo_next(stackframeinfo_t *tmpsfi)
{
- methodinfo *m;
- void *pv;
- void *xpc;
- int32_t linenumber;
-
- /* Get values from the stackframeinfo. */
-
- m = sfi->method;
- pv = sfi->pv;
- xpc = sfi->xpc;
-
- /* Skip builtin methods. */
-
- if (m->flags & ACC_METHOD_BUILTIN)
- return stb;
-
- /* Search the line number table. */
-
- linenumber = dseg_get_linenumber_from_pc(&m, pv, xpc);
-
- /* Add a new entry to the staktrace. */
-
- stb = stacktrace_entry_add(stb, m, linenumber);
+ codeinfo *code;
+ void *pv;
+ void *sp;
+ void *ra;
+ void *xpc;
+ uint32_t framesize;
+ stackframeinfo_t *prevsfi;
- return stb;
-}
-
-
-/* stacktrace_stack_walk *******************************************************
-
- Walk the stack (or the stackframeinfo-chain) to the next method.
+ /* Sanity check. */
- IN:
- sfi....stackframeinfo of current method
-
-*******************************************************************************/
-
-static inline void stacktrace_stack_walk(stackframeinfo *sfi)
-{
- methodinfo *m;
- void *pv;
- void *sp;
- void *ra;
- void *xpc;
- uint32_t framesize;
+ assert(tmpsfi != NULL);
/* Get values from the stackframeinfo. */
- m = sfi->method;
- pv = sfi->pv;
- sp = sfi->sp;
- ra = sfi->ra;
- xpc = sfi->xpc;
-
+ 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));
else
# endif
{
- /* TODO Remove jd->isleafmethod and use the flags in
- codeinfo. */
-
-/* if (!CODE_IS_LEAFMETHOD(m->code)) { */
- int32_t isleafmethod = *((int32_t *) (((intptr_t) pv) + IsLeaf));
- if (!isleafmethod) {
+ if (!code_is_leafmethod(code))
ra = md_stacktrace_get_returnaddress(sp, framesize);
- }
}
#else
ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
#endif
}
- /* Get the methodinfo pointer for the parent Java method. */
+ /* Get the codeinfo pointer for the parent Java method. */
- m = code_get_methodinfo_for_pv(pv);
+ code = code_get_codeinfo_for_pv(pv);
/* Calculate the SP for the parent Java method. */
#endif
}
- /* 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. */
+ /* 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. */
+
+ if (code == NULL) {
+ prevsfi = tmpsfi->prev;
+
+ /* 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 (prevsfi == NULL) {
+ tmpsfi->code = NULL;
+ tmpsfi->prev = NULL;
+ return;
+ }
+
+ /* Fill the temporary stackframeinfo with the new values. */
+
+ 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);
+ }
+
+#if !defined(NDEBUG)
+ /* Print current method information. */
- sfi->method = m;
- sfi->pv = pv;
- sfi->sp = sp;
- sfi->ra = ra;
- sfi->xpc = (void *) (((intptr_t) ra) - 1);
+ 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_create ***********************************************************
+/* stacktrace_stackframeinfo_end_check *****************************************
- 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).
+ Check if we reached the end of the stacktrace.
- RETURN VALUE:
- pointer to the stacktracebuffer, or
- NULL if there is no stacktrace available for the
- given thread.
+ IN:
+ tmpsfi ... temporary stackframeinfo of current method
+
+ RETURN:
+ true .... the end is reached
+ false ... the end is not reached
*******************************************************************************/
-stacktracebuffer *stacktrace_create(stackframeinfo *sfi)
+static inline bool stacktrace_stackframeinfo_end_check(stackframeinfo_t *tmpsfi)
{
- stacktracebuffer *stb;
- stackframeinfo tmpsfi;
-
- /* Create a stacktracebuffer in dump memory. */
+ /* Sanity check. */
- stb = DNEW(stacktracebuffer);
-
- stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
- stb->used = 0;
+ assert(tmpsfi != NULL);
+ if ((tmpsfi->code == NULL) && (tmpsfi->prev == NULL)) {
#if !defined(NDEBUG)
- if (opt_DebugStackTrace) {
- printf("\n\n---> stacktrace creation start (fillInStackTrace):\n");
- fflush(stdout);
- }
+ if (opt_DebugStackTrace)
+ log_println("[stacktrace stop]");
#endif
- /* Put the data from the stackframeinfo into a temporary one. */
+ return true;
+ }
- /* XXX This is not correct, but a workaround for threads-dump for
- now. */
-/* assert(sfi != NULL); */
- if (sfi == NULL)
- return NULL;
+ return false;
+}
- tmpsfi.method = sfi->method;
- tmpsfi.pv = sfi->pv;
- tmpsfi.sp = sfi->sp;
- tmpsfi.ra = sfi->ra;
- tmpsfi.xpc = sfi->xpc;
- /* Iterate till we're done. */
+/* stacktrace_depth ************************************************************
- for (;;) {
-#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.method, tmpsfi.pv, tmpsfi.sp, tmpsfi.ra,
- tmpsfi.xpc);
- method_print(tmpsfi.method);
- log_print("]");
- log_finish();
- }
-#endif
+ Calculates and returns the depth of the current stacktrace.
- /* Check for Throwable.fillInStackTrace(). */
+ IN:
+ sfi ... stackframeinfo where to start the stacktrace
-/* if (tmpsfi.method->name != utf_fillInStackTrace) { */
-
- /* Add this method to the stacktrace. */
+ RETURN:
+ depth of the stacktrace
- stb = stacktrace_method_add(stb, &tmpsfi);
-/* } */
+*******************************************************************************/
- /* Walk the stack (or the stackframeinfo chain) and get the
- next method. */
+static int stacktrace_depth(stackframeinfo_t *sfi)
+{
+ stackframeinfo_t tmpsfi;
+ int depth;
+ methodinfo *m;
- stacktrace_stack_walk(&tmpsfi);
+#if !defined(NDEBUG)
+ if (opt_DebugStackTrace)
+ log_println("[stacktrace_depth]");
+#endif
- /* If the new methodinfo 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. */
+ /* XXX This is not correct, but a workaround for threads-dump for
+ now. */
+/* assert(sfi != NULL); */
+ if (sfi == NULL)
+ return 0;
- if (tmpsfi.method == NULL) {
- sfi = sfi->prev;
+ /* Iterate over all stackframes. */
- /* If the previous stackframeinfo in the chain is NULL we
- reached the top of the stacktrace and leave the
- loop. */
+ depth = 0;
- if (sfi == NULL)
- break;
+ for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
+ stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
+ stacktrace_stackframeinfo_next(&tmpsfi)) {
+ /* Get methodinfo. */
- /* Fill the temporary stackframeinfo with the new
- values. */
+ m = tmpsfi.code->m;
- tmpsfi.method = sfi->method;
- tmpsfi.pv = sfi->pv;
- tmpsfi.sp = sfi->sp;
- tmpsfi.ra = sfi->ra;
- tmpsfi.xpc = sfi->xpc;
- }
- }
+ /* Skip builtin methods. */
-#if !defined(NDEBUG)
- if (opt_DebugStackTrace) {
- printf("---> stacktrace creation finished.\n\n");
- fflush(stdout);
- }
-#endif
+ if (m->flags & ACC_METHOD_BUILTIN)
+ continue;
- /* return the stacktracebuffer */
+ depth++;
+ }
- if (stb->used == 0)
- return NULL;
- else
- return stb;
+ return depth;
}
-/* stacktrace_fillInStackTrace *************************************************
+/* stacktrace_get **************************************************************
+
+ 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.
- Generate a stacktrace from the current thread for
- java.lang.VMThrowable.fillInStackTrace.
+ RETURN:
+ stacktrace as Java byte-array
*******************************************************************************/
-java_handle_bytearray_t *stacktrace_fillInStackTrace(void)
+java_handle_bytearray_t *stacktrace_get(void)
{
- stacktracebuffer *stb;
+ stackframeinfo_t *sfi;
+ stackframeinfo_t tmpsfi;
+ int depth;
java_handle_bytearray_t *ba;
- s4 ba_size;
- s4 dumpsize;
+ int32_t ba_size;
+ stacktrace_t *st;
+ stacktrace_entry_t *ste;
+ methodinfo *m;
+ bool skip_fillInStackTrace;
+ bool skip_init;
+
CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
- /* mark start of dump memory area */
+#if !defined(NDEBUG)
+ if (opt_DebugStackTrace)
+ log_println("[stacktrace_get]");
+#endif
- dumpsize = dump_size();
+ skip_fillInStackTrace = true;
+ skip_init = true;
- /* create a stacktrace from the current thread */
+ /* Get the stacktrace depth of the current thread. */
- stb = stacktrace_create(STACKFRAMEINFO);
+ sfi = STACKFRAMEINFO;
- if (stb == NULL)
- goto return_NULL;
+ depth = stacktrace_depth(sfi);
+
+ if (depth == 0)
+ return NULL;
- /* allocate memory from the GC heap and copy the stacktrace buffer */
- /* ATTENTION: use a bytearray for this to not confuse the GC */
+ /* 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. */
+
+ ba_size = sizeof(stacktrace_t) + sizeof(stacktrace_entry_t) * depth;
- ba_size = sizeof(stacktracebuffer) +
- sizeof(stacktrace_entry) * stb->used -
- sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_DEFAULT;
ba = builtin_newarray_byte(ba_size);
if (ba == NULL)
goto return_NULL;
- MCOPY(LLNI_array_data(ba), stb, u1, ba_size);
+ /* Get a stacktrace entry pointer. */
+ /* ATTENTION: We need a critical section here because we use the
+ byte-array data pointer directly. */
+
+ LLNI_CRITICAL_START;
+
+ st = (stacktrace_t *) LLNI_array_data(ba);
+
+ ste = st->entries;
+
+ /* Iterate over the whole stack. */
+
+ for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
+ stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
+ stacktrace_stackframeinfo_next(&tmpsfi)) {
+ /* Get the methodinfo. */
+
+ m = tmpsfi.code->m;
+
+ /* Skip builtin methods. */
+
+ if (m->flags & ACC_METHOD_BUILTIN)
+ continue;
+
+ /* This logic is taken from
+ hotspot/src/share/vm/classfile/javaClasses.cpp
+ (java_lang_Throwable::fill_in_stack_trace). */
+
+ if (skip_fillInStackTrace == true) {
+ /* Check "fillInStackTrace" only once, so we negate the
+ flag after the first time check. */
+
+#if defined(WITH_CLASSPATH_GNU)
+ /* For GNU Classpath we also need to skip
+ VMThrowable.fillInStackTrace(). */
+
+ if ((m->class == class_java_lang_VMThrowable) &&
+ (m->name == utf_fillInStackTrace))
+ continue;
+#endif
+
+ skip_fillInStackTrace = false;
+
+ if (m->name == utf_fillInStackTrace)
+ continue;
+ }
+
+ /* 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 (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. */
+
+ skip_init = false;
+ }
+ }
+
+ /* Store the stacktrace entry and increment the pointer. */
+
+ ste->code = tmpsfi.code;
+ ste->pc = tmpsfi.xpc;
+
+ ste++;
+ }
+
+ /* Store the number of entries in the stacktrace structure. */
+
+ st->length = ste - st->entries;
+
+ LLNI_CRITICAL_END;
/* release dump memory */
- dump_release(dumpsize);
+/* dump_release(dumpsize); */
CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
stacktrace_overhead)
return ba;
return_NULL:
- dump_release(dumpsize);
+/* dump_release(dumpsize); */
CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
stacktrace_overhead)
}
+/* stacktrace_first_nonnull_classloader ****************************************
+
+ Returns the first non-null (user-defined) classloader on the stack.
+ If none is found NULL is returned.
+
+ RETURN:
+ classloader
+
+*******************************************************************************/
+
+classloader *stacktrace_first_nonnull_classloader(void)
+{
+ stackframeinfo_t *sfi;
+ stackframeinfo_t tmpsfi;
+ methodinfo *m;
+ classloader *cl;
+
+#if !defined(NDEBUG)
+ if (opt_DebugStackTrace)
+ log_println("[stacktrace_first_nonnull_classloader]");
+#endif
+
+ /* Get the stackframeinfo of the current thread. */
+
+ sfi = STACKFRAMEINFO;
+
+ /* Iterate over the whole stack. */
+
+ for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
+ stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
+ stacktrace_stackframeinfo_next(&tmpsfi)) {
+
+ m = tmpsfi.code->m;
+ cl = class_get_classloader(m->class);
+
+ if (cl != NULL)
+ return cl;
+ }
+
+ return NULL;
+}
+
+
/* stacktrace_getClassContext **************************************************
Creates a Class context array.
java_handle_objectarray_t *stacktrace_getClassContext(void)
{
- stacktracebuffer *stb;
- stacktrace_entry *ste;
- java_handle_objectarray_t *oa;
- s4 oalength;
- s4 i;
- s4 dumpsize;
+ stackframeinfo_t *sfi;
+ stackframeinfo_t tmpsfi;
+ int depth;
+ java_handle_objectarray_t *oa;
+ java_object_t **data;
+ int i;
+ methodinfo *m;
+
CYCLES_STATS_DECLARE_AND_START
- /* mark start of dump memory area */
+#if !defined(NDEBUG)
+ if (opt_DebugStackTrace)
+ log_println("[stacktrace_getClassContext]");
+#endif
- dumpsize = dump_size();
+ sfi = STACKFRAMEINFO;
- /* create a stacktrace for the current thread */
+ /* Get the depth of the current stack. */
- stb = stacktrace_create(STACKFRAMEINFO);
+ depth = stacktrace_depth(sfi);
- if (stb == NULL)
- goto return_NULL;
+ /* The first stackframe corresponds to the method whose
+ implementation calls this native function. We remove that
+ entry. */
- /* calculate the size of the Class array */
+ depth--;
+ stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
+ stacktrace_stackframeinfo_next(&tmpsfi);
- for (i = 0, oalength = 0; i < stb->used; i++)
- if (stb->entries[i].method != NULL)
- oalength++;
+ /* Allocate the Class array. */
- /* The first entry corresponds to the method whose implementation */
- /* calls stacktrace_getClassContext. We remove that entry. */
+ oa = builtin_anewarray(depth, class_java_lang_Class);
- ste = &(stb->entries[0]);
- ste++;
- oalength--;
+ if (oa == NULL) {
+ CYCLES_STATS_END(stacktrace_getClassContext);
- /* allocate the Class array */
+ return NULL;
+ }
- oa = builtin_anewarray(oalength, class_java_lang_Class);
- if (!oa)
- goto return_NULL;
+ /* Fill the Class array from the stacktrace list. */
- /* fill the Class array from the stacktracebuffer */
+ LLNI_CRITICAL_START;
- for(i = 0; i < oalength; i++, ste++) {
- if (ste->method == NULL) {
- i--;
- continue;
- }
+ data = LLNI_array_data(oa);
- LLNI_array_direct(oa, i) = (java_object_t *) ste->method->class;
- }
+ /* Iterate over the whole stack. */
- /* release dump memory */
+ i = 0;
- dump_release(dumpsize);
+ for (;
+ stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
+ stacktrace_stackframeinfo_next(&tmpsfi)) {
+ /* Get methodinfo. */
- CYCLES_STATS_END(stacktrace_getClassContext)
+ m = tmpsfi.code->m;
- return oa;
+ /* Skip builtin methods. */
-return_NULL:
- dump_release(dumpsize);
+ if (m->flags & ACC_METHOD_BUILTIN)
+ continue;
+
+ /* Store the class in the array. */
+
+ data[i] = (java_object_t *) m->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(STACKFRAMEINFO);
+ sfi = STACKFRAMEINFO;
- if (stb == NULL)
- goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
+ /* If the stackframeinfo is NULL then FindClass is called through
+ the Invocation Interface and we return NULL */
- /* iterate over all stacktrace entries and find the first suitable
- class */
+ if (sfi == NULL) {
+ CYCLES_STATS_END(stacktrace_getCurrentClass);
- for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
- m = ste->method;
+ return NULL;
+ }
- if (m == NULL)
- continue;
+ /* Iterate over the whole stack. */
- if (m->class == class_java_security_PrivilegedAction)
- goto return_NULL;
+ for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
+ stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
+ stacktrace_stackframeinfo_next(&tmpsfi)) {
+ /* Get the methodinfo. */
- if (m->class != NULL) {
- dump_release(dumpsize);
+ m = tmpsfi.code->m;
- CYCLES_STATS_END(stacktrace_getCurrentClass)
+ if (m->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_handle_objectarray_t *stacktrace_getStack(void)
+#if defined(ENABLE_JAVASE) && defined(WITH_CLASSPATH_GNU)
+java_handle_objectarray_t *stacktrace_get_stack(void)
{
- stacktracebuffer *stb;
- stacktrace_entry *ste;
+ stackframeinfo_t *sfi;
+ stackframeinfo_t tmpsfi;
+ int depth;
java_handle_objectarray_t *oa;
java_handle_objectarray_t *classes;
java_handle_objectarray_t *methodnames;
- classinfo *c;
+ methodinfo *m;
java_handle_t *string;
- s4 i;
- s4 dumpsize;
- CYCLES_STATS_DECLARE_AND_START
+ int i;
- /* mark start of dump memory area */
+ CYCLES_STATS_DECLARE_AND_START
- dumpsize = dump_size();
+#if !defined(NDEBUG)
+ if (opt_DebugStackTrace)
+ log_println("[stacktrace_get_stack]");
+#endif
- /* create a stacktrace for the current thread */
+ /* Get the stackframeinfo of the current thread. */
- stb = stacktrace_create(STACKFRAMEINFO);
+ sfi = 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);
- /* iterate over all stacktrace entries */
+ /* Iterate over the whole stack. */
+ /* TODO We should use a critical section here to speed things
+ up. */
+
+ i = 0;
+
+ for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
+ stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
+ stacktrace_stackframeinfo_next(&tmpsfi)) {
+ /* Get the methodinfo. */
+
+ m = tmpsfi.code->m;
+
+ /* Skip builtin methods. */
+
+ if (m->flags & ACC_METHOD_BUILTIN)
+ continue;
- for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
- c = ste->method->class;
+ /* 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 *) c;
+ LLNI_array_direct(classes, i) = (java_object_t *) m->class;
- string = javastring_new(ste->method->name);
+ /* Store the name in the array. */
+
+ string = javastring_new(m->name);
if (string == NULL)
goto return_NULL;
array_objectarray_element_set(methodnames, i, string);
- }
- /* return the 2-dimensional array */
-
- 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 ************************************************************
-/* stacktrace_print_trace_from_buffer ******************************************
+ Print the given stacktrace with CACAO intern methods only (no Java
+ code required).
- 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.
+ 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_print_trace ******************************************************
+/* stacktrace_print_exception **************************************************
- Print the stacktrace of a given exception. More or less a wrapper
- to stacktrace_print_trace_from_buffer.
+ Print the stacktrace of a given exception (more or less a wrapper
+ to stacktrace_print).
+
+ IN:
+ h ... handle of exception to print
*******************************************************************************/
-void stacktrace_print_trace(java_handle_t *xptr)
+void stacktrace_print_exception(java_handle_t *h)
{
- java_lang_Throwable *t;
+ java_lang_Throwable *o;
+
#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
+
java_handle_bytearray_t *ba;
- stacktracebuffer *stb;
+ stacktrace_t *st;
- t = (java_lang_Throwable *) xptr;
+ o = (java_lang_Throwable *) h;
- if (t == NULL)
+ if (o == NULL)
return;
/* now print the stacktrace */
#if defined(WITH_CLASSPATH_GNU)
- LLNI_field_get_ref(t, vmState, vmt);
- LLNI_field_get_ref(vmt, vmData, ba);
+
+ LLNI_field_get_ref(o, vmState, vmt);
+ LLNI_field_get_ref(vmt, vmData, backtrace);
+
#elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
- LLNI_field_get_ref(t, backtrace, ba);
+
+ LLNI_field_get_ref(o, backtrace, backtrace);
+
#else
# error unknown classpath configuration
#endif
- assert(ba);
- stb = (stacktracebuffer *) LLNI_array_data(ba);
+ ba = (java_handle_bytearray_t *) backtrace;
+
+ /* Sanity check. */
+
+ assert(ba != NULL);
+
+ /* We need a critical section here as we use the byte-array data
+ pointer directly. */
+
+ LLNI_CRITICAL_START;
+
+ st = (stacktrace_t *) LLNI_array_data(ba);
+
+ stacktrace_print(st);
- stacktrace_print_trace_from_buffer(stb);
+ LLNI_CRITICAL_END;
}
#if defined(ENABLE_CYCLES_STATS)
void stacktrace_print_cycles_stats(FILE *file)
{
- CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
- CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
- CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
- CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
- CYCLES_STATS_PRINT(stacktrace_getStack ,file);
+ CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead, file);
+ CYCLES_STATS_PRINT(stacktrace_get, file);
+ CYCLES_STATS_PRINT(stacktrace_getClassContext , file);
+ CYCLES_STATS_PRINT(stacktrace_getCurrentClass , file);
+ CYCLES_STATS_PRINT(stacktrace_get_stack, file);
}
#endif