Merged with tip.
[cacao.git] / src / vm / jit / stacktrace.c
index 15f7beb6baab0edad3b7e8480a440d703a30a2ad..461c09d18f68d38ff92196ac1ad0f2daf64febab 100644 (file)
@@ -1,9 +1,7 @@
 /* src/vm/jit/stacktrace.c - machine independent stacktrace system
 
-   Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
-   C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
-   E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
-   J. Wenninger, Institut f. Computersprachen - TU Wien
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
 
    This file is part of CACAO.
 
@@ -34,6 +32,8 @@
 
 #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
 
-#if defined(ENABLE_THREADS)
-# include "threads/native/threads.h"
-#else
-# include "threads/none/threads.h"
-#endif
+#include "threads/thread.h"
 
 #include "toolbox/logging.h"
 
 
 #include "vm/jit/asmpart.h"
 #include "vm/jit/codegen-common.h"
+#include "vm/jit/linenumbertable.h"
 #include "vm/jit/methodheader.h"
+#include "vm/jit/methodtree.h"
 
 #include "vmcore/class.h"
 #include "vmcore/loader.h"
+#include "vmcore/method.h"
 #include "vmcore/options.h"
 
 
 /* global variables ***********************************************************/
-#if !defined(ENABLE_THREADS)
-stackframeinfo *_no_threads_stackframeinfo = NULL;
-#endif
 
-CYCLES_STATS_DECLARE(stacktrace_overhead        ,100,1)
-CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace,40,5000)
-CYCLES_STATS_DECLARE(stacktrace_getClassContext ,40,5000)
-CYCLES_STATS_DECLARE(stacktrace_getCurrentClass ,40,5000)
-CYCLES_STATS_DECLARE(stacktrace_getStack        ,40,10000)
+CYCLES_STATS_DECLARE(stacktrace_overhead        , 100, 1)
+CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace, 40,  5000)
+CYCLES_STATS_DECLARE(stacktrace_get,              40,  5000)
+CYCLES_STATS_DECLARE(stacktrace_getClassContext , 40,  5000)
+CYCLES_STATS_DECLARE(stacktrace_getCurrentClass , 40,  5000)
+CYCLES_STATS_DECLARE(stacktrace_get_stack       , 40,  10000)
 
 
 /* stacktrace_stackframeinfo_add ***********************************************
@@ -91,20 +91,17 @@ CYCLES_STATS_DECLARE(stacktrace_getStack        ,40,10000)
 
 *******************************************************************************/
 
-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 *currentsfi;
+       codeinfo         *code;
 #if defined(ENABLE_JIT)
-       s4               framesize;
+       s4                 framesize;
 #endif
 
-       /* get current stackframe info pointer */
+       /* Get current stackframe info. */
 
-       psfi = &STACKFRAMEINFO;
+       currentsfi = threads_get_current_stackframeinfo();
 
        /* sometimes we don't have pv handy (e.g. in asmpart.S:
        L_asm_call_jit_compiler_exception or in the interpreter). */
@@ -112,7 +109,7 @@ void stacktrace_stackframeinfo_add(stackframeinfo *sfi, u1 *pv, u1 *sp, u1 *ra,
        if (pv == NULL) {
 #if defined(ENABLE_INTRP)
                if (opt_intrp)
-                       pv = codegen_get_pv_from_pc(ra);
+                       pv = methodtree_find(ra);
                else
 #endif
                        {
@@ -126,12 +123,12 @@ void stacktrace_stackframeinfo_add(stackframeinfo *sfi, u1 *pv, u1 *sp, u1 *ra,
                        }
        }
 
-       /* 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); */
+       /*      assert(m != NULL); */
 
 #if defined(ENABLE_JIT)
 # if defined(ENABLE_INTRP)
@@ -150,14 +147,13 @@ void stacktrace_stackframeinfo_add(stackframeinfo *sfi, u1 *pv, u1 *sp, u1 *ra,
 
                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);
@@ -179,16 +175,27 @@ void stacktrace_stackframeinfo_add(stackframeinfo *sfi, u1 *pv, u1 *sp, u1 *ra,
 
        /* Fill new stackframeinfo structure. */
 
-       sfi->prev   = *psfi;
-       sfi->method = m;
-       sfi->pv     = pv;
-       sfi->sp     = sp;
-       sfi->ra     = ra;
-       sfi->xpc    = xpc;
+       sfi->prev = currentsfi;
+       sfi->code = code;
+       sfi->pv   = pv;
+       sfi->sp   = sp;
+       sfi->ra   = ra;
+       sfi->xpc  = xpc;
+
+#if !defined(NDEBUG)
+       if (opt_DebugStackFrameInfo) {
+               log_start();
+               log_print("[stackframeinfo add   : sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
+                                 sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
+               method_print(sfi->code->m);
+               log_print("]");
+               log_finish();
+       }
+#endif
 
        /* Store new stackframeinfo pointer. */
 
-       *psfi = sfi;
+       threads_set_current_stackframeinfo(sfi);
 
        /* set the native world flag for the current thread */
        /* ATTENTION: This flag tells the GC how to treat this thread in case of
@@ -205,151 +212,111 @@ void stacktrace_stackframeinfo_add(stackframeinfo *sfi, u1 *pv, u1 *sp, u1 *ra,
 
 *******************************************************************************/
 
-void stacktrace_stackframeinfo_remove(stackframeinfo *sfi)
+void stacktrace_stackframeinfo_remove(stackframeinfo_t *sfi)
 {
-       stackframeinfo **psfi;
-
-       /* clear the native world flag for the current thread */
-       /* ATTENTION: Clear this flag _before_ removing the stackframe info */
+       /* Clear the native world flag for the current thread. */
+       /* ATTENTION: Clear this flag _before_ removing the stackframe info. */
 
        THREAD_NATIVEWORLD_EXIT;
 
-       /* get current stackframe info pointer */
-
-       psfi = &STACKFRAMEINFO;
-
-       /* restore the old pointer */
-
-       *psfi = sfi->prev;
-}
-
-
-/* stacktrace_entry_add ********************************************************
-
-   Adds a new entry to the stacktrace buffer.
-
-*******************************************************************************/
-
-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 = DMREALLOC(stb, u1, stb_size_old, stb_size_new);
-
-               /* set new buffer capacity */
-
-               stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
+#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
 
-       /* insert the current entry */
-
-       ste = &(stb->entries[stb->used]);
-
-       ste->method     = m;
-       ste->linenumber = line;
-
-       /* increase entries used count */
-
-       stb->used += 1;
+       /* Set previous stackframe info. */
 
-       return stb;
+       threads_set_current_stackframeinfo(sfi->prev);
 }
 
 
-/* stacktrace_method_add *******************************************************
+/* stacktrace_stackframeinfo_fill **********************************************
 
-   Add stacktrace entries[1] for the given method to the stacktrace
-   buffer.
+   Fill the temporary stackframeinfo structure with the values given
+   in sfi.
 
    IN:
-       stb....stacktracebuffer to fill
-          sfi....current stackframeinfo
-   OUT:
-       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)
+       tmpsfi ... temporary stackframeinfo
+       sfi ...... stackframeinfo to be used in the next iteration
 
 *******************************************************************************/
 
-static inline stacktracebuffer *stacktrace_method_add(stacktracebuffer *stb, stackframeinfo *sfi)
+static inline void stacktrace_stackframeinfo_fill(stackframeinfo_t *tmpsfi, stackframeinfo_t *sfi)
 {
-       methodinfo *m;
-       void       *pv;
-       void       *xpc;
-       int32_t     linenumber;
+       /* Sanity checks. */
 
-       /* Get values from the stackframeinfo. */
+       assert(tmpsfi != NULL);
+       assert(sfi != NULL);
 
-       m   = sfi->method;
-       pv  = sfi->pv;
-       xpc = sfi->xpc;
+       /* Fill the temporary stackframeinfo. */
 
-       /* Skip builtin methods. */
+       tmpsfi->code = sfi->code;
+       tmpsfi->pv   = sfi->pv;
+       tmpsfi->sp   = sfi->sp;
+       tmpsfi->ra   = sfi->ra;
+       tmpsfi->xpc  = sfi->xpc;
 
-       if (m->flags & ACC_METHOD_BUILTIN)
-               return stb;
-
-       /* Search the line number table. */
-
-       linenumber = dseg_get_linenumber_from_pc(&m, pv, xpc);
+       /* Set the previous stackframe info of the temporary one to the
+          next in the chain. */
 
-       /* Add a new entry to the staktrace. */
+       tmpsfi->prev = sfi->prev;
 
-       stb = stacktrace_entry_add(stb, m, linenumber);
-
-       return stb;
+#if !defined(NDEBUG)
+       if (opt_DebugStackTrace)
+               log_println("[stacktrace fill]");
+#endif
 }
 
 
-/* stacktrace_stack_walk *******************************************************
+/* 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.
 
-   Walk the stack (or the stackframeinfo-chain) to the next method.
+   ATTENTION: This function does NOT skip builtin methods!
 
    IN:
-       sfi....stackframeinfo of current method
+       tmpsfi ... temporary stackframeinfo of current method
 
 *******************************************************************************/
 
-static inline void stacktrace_stack_walk(stackframeinfo *sfi)
+static inline void stacktrace_stackframeinfo_next(stackframeinfo_t *tmpsfi)
 {
-       methodinfo *m;
-       void       *pv;
-       void       *sp;
-       void       *ra;
-       void       *xpc;
-       uint32_t    framesize;
+       codeinfo         *code;
+       void             *pv;
+       void             *sp;
+       void             *ra;
+       void             *xpc;
+       uint32_t          framesize;
+       stackframeinfo_t *prevsfi;
 
-       /* Get values from the stackframeinfo. */
+       /* Sanity check. */
 
-       m   = sfi->method;
-       pv  = sfi->pv;
-       sp  = sfi->sp;
-       ra  = sfi->ra;
-       xpc = sfi->xpc;
+       assert(tmpsfi != NULL);
 
+       /* Get values from the stackframeinfo. */
+
+       code = tmpsfi->code;
+       pv   = tmpsfi->pv;
+       sp   = tmpsfi->sp;
+       ra   = tmpsfi->ra;
+       xpc  = tmpsfi->xpc;
        /* Get the current stack frame size. */
 
        framesize = *((uint32_t *) (((intptr_t) pv) + FrameSize));
 
        /* Get the RA of the current stack frame (RA to the parent Java
-          method). */
+          method) if the current method is a non-leaf method.  Otherwise
+          the value in the stackframeinfo is correct (from the signal
+          handler). */
 
 #if defined(ENABLE_JIT)
 # if defined(ENABLE_INTRP)
@@ -357,7 +324,10 @@ static inline void stacktrace_stack_walk(stackframeinfo *sfi)
                ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
        else
 # endif
-               ra = md_stacktrace_get_returnaddress(sp, framesize);
+               {
+                       if (!code_is_leafmethod(code))
+                               ra = md_stacktrace_get_returnaddress(sp, framesize);
+               }
 #else
        ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
 #endif
@@ -366,7 +336,7 @@ static inline void stacktrace_stack_walk(stackframeinfo *sfi)
 
 #if defined(ENABLE_INTRP)
        if (opt_intrp)
-               pv = codegen_get_pv_from_pc(ra);
+               pv = methodtree_find(ra);
        else
 #endif
                {
@@ -380,9 +350,9 @@ static inline void stacktrace_stack_walk(stackframeinfo *sfi)
 #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. */
 
@@ -401,190 +371,284 @@ static inline void stacktrace_stack_walk(stackframeinfo *sfi)
 #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);
+       }
 
-       sfi->method = m;
-       sfi->pv     = pv;
-       sfi->sp     = sp;
-       sfi->ra     = ra;
-       sfi->xpc    = (void *) (((intptr_t) ra) - 1);
+#if !defined(NDEBUG)
+       /* Print current method information. */
+
+       if (opt_DebugStackTrace) {
+               log_start();
+               log_print("[stacktrace: method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
+                                 tmpsfi->code->m, tmpsfi->pv, tmpsfi->sp, tmpsfi->ra,
+                                 tmpsfi->xpc);
+               method_print(tmpsfi->code->m);
+               log_print("]");
+               log_finish();
+       }
+#endif
 }
 
 
-/* stacktrace_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
+
+   RETURN:
+       depth of the stacktrace
 
-/*             if (tmpsfi.method->name != utf_fillInStackTrace) { */
-                       
-                       /* Add this method to the stacktrace. */
+*******************************************************************************/
+
+static int stacktrace_depth(stackframeinfo_t *sfi)
+{
+       stackframeinfo_t  tmpsfi;
+       int               depth;
+       methodinfo       *m;
 
-                       stb = stacktrace_method_add(stb, &tmpsfi);
-/*             } */
+#if !defined(NDEBUG)
+       if (opt_DebugStackTrace)
+               log_println("[stacktrace_depth]");
+#endif
 
-               /* Walk the stack (or the stackframeinfo chain) and get the
-                  next method. */
+       /* XXX This is not correct, but a workaround for threads-dump for
+          now. */
+/*     assert(sfi != NULL); */
+       if (sfi == NULL)
+               return 0;
 
-               stacktrace_stack_walk(&tmpsfi);
+       /* Iterate over all stackframes. */
 
-               /* 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. */
+       depth = 0;
 
-               if (tmpsfi.method == NULL) {
-                       sfi = sfi->prev;
+       for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
+                stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
+                stacktrace_stackframeinfo_next(&tmpsfi)) {
+               /* Get methodinfo. */
 
-                       /* If the previous stackframeinfo in the chain is NULL we
-                          reached the top of the stacktrace and leave the
-                          loop. */
+               m = tmpsfi.code->m;
 
-                       if (sfi == NULL)
-                               break;
+               /* Skip builtin methods. */
 
-                       /* Fill the temporary stackframeinfo with the new
-                          values. */
+               if (m->flags & ACC_METHOD_BUILTIN)
+                       continue;
 
-                       tmpsfi.method = sfi->method;
-                       tmpsfi.pv     = sfi->pv;
-                       tmpsfi.sp     = sfi->sp;
-                       tmpsfi.ra     = sfi->ra;
-                       tmpsfi.xpc    = sfi->xpc;
-               }
+               depth++;
        }
 
-#if !defined(NDEBUG)
-       if (opt_DebugStackTrace) {
-               printf("---> stacktrace creation finished.\n\n");
-               fflush(stdout);
-       }
-#endif
+       return depth;
+}
 
-       /* return the stacktracebuffer */
 
-       if (stb->used == 0)
-               return NULL;
-       else
-               return stb;
-}
+/* stacktrace_get **************************************************************
 
+   Builds and returns a stacktrace starting from the given stackframe
+   info and returns the stacktrace structure wrapped in a Java
+   byte-array to not confuse the GC.
 
-/* stacktrace_fillInStackTrace *************************************************
+   IN:
+       sfi ... stackframe info to start stacktrace from
 
-   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(stackframeinfo_t *sfi)
 {
-       stacktracebuffer        *stb;
+       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 */
+       depth = stacktrace_depth(sfi);
 
-       stb = stacktrace_create(STACKFRAMEINFO);
+       if (depth == 0)
+               return NULL;
 
-       if (stb == NULL)
-               goto return_NULL;
+       /* 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. */
 
-       /* allocate memory from the GC heap and copy the stacktrace buffer */
-       /* ATTENTION: use a bytearray for this to not confuse the GC */
+       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->clazz == 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) &&
+                               (class_issubclass(m->clazz, class_java_lang_Throwable))) {
+                               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)
@@ -593,6 +657,148 @@ return_NULL:
 }
 
 
+/* stacktrace_get_current ******************************************************
+
+   Builds and returns a stacktrace from the current thread and returns
+   the stacktrace structure wrapped in a Java byte-array to not
+   confuse the GC.
+
+   RETURN:
+       stacktrace as Java byte-array
+
+*******************************************************************************/
+
+java_handle_bytearray_t *stacktrace_get_current(void)
+{
+       stackframeinfo_t        *sfi;
+       java_handle_bytearray_t *ba;
+
+       sfi = threads_get_current_stackframeinfo();
+       ba  = stacktrace_get(sfi);
+
+       return ba;
+}
+
+
+/* stacktrace_get_caller_class *************************************************
+
+   Get the class on the stack at the given depth.  This function skips
+   various special classes or methods.
+
+   ARGUMENTS:
+       depth ... depth to get caller class of
+
+   RETURN:
+       caller class
+
+*******************************************************************************/
+
+#if defined(ENABLE_JAVASE)
+classinfo *stacktrace_get_caller_class(int depth)
+{
+       stackframeinfo_t *sfi;
+       stackframeinfo_t  tmpsfi;
+       methodinfo       *m;
+       classinfo        *c;
+       int               i;
+
+#if !defined(NDEBUG)
+       if (opt_DebugStackTrace)
+               log_println("[stacktrace_get_caller_class]");
+#endif
+
+       /* Get the stackframeinfo of the current thread. */
+
+       sfi = threads_get_current_stackframeinfo();
+
+       /* Iterate over the whole stack until we reached the requested
+          depth. */
+
+       i = 0;
+
+       for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
+                stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
+                stacktrace_stackframeinfo_next(&tmpsfi)) {
+
+               m = tmpsfi.code->m;
+               c = m->clazz;
+
+               /* Skip builtin methods. */
+
+               if (m->flags & ACC_METHOD_BUILTIN)
+                       continue;
+
+#if defined(WITH_CLASSPATH_SUN)
+               /* NOTE: See hotspot/src/share/vm/runtime/vframe.cpp
+                  (vframeStreamCommon::security_get_caller_frame). */
+
+               /* This is java.lang.reflect.Method.invoke(), skip it. */
+
+               if (m == method_java_lang_reflect_Method_invoke)
+                       continue;
+
+               /* This is an auxiliary frame, skip it. */
+
+               if (class_issubclass(c, class_sun_reflect_MagicAccessorImpl))
+                       continue;
+#endif
+
+               /* We reached the requested depth. */
+
+               if (i >= depth)
+                       return c;
+
+               i++;
+       }
+
+       return NULL;
+}
+#endif
+
+
+/* stacktrace_first_nonnull_classloader ****************************************
+
+   Returns the first non-null (user-defined) classloader on the stack.
+   If none is found NULL is returned.
+
+   RETURN:
+       classloader
+
+*******************************************************************************/
+
+classloader_t *stacktrace_first_nonnull_classloader(void)
+{
+       stackframeinfo_t *sfi;
+       stackframeinfo_t  tmpsfi;
+       methodinfo       *m;
+       classloader_t    *cl;
+
+#if !defined(NDEBUG)
+       if (opt_DebugStackTrace)
+               log_println("[stacktrace_first_nonnull_classloader]");
+#endif
+
+       /* Get the stackframeinfo of the current thread. */
+
+       sfi = threads_get_current_stackframeinfo();
+
+       /* Iterate over the whole stack. */
+
+       for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
+                stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
+                stacktrace_stackframeinfo_next(&tmpsfi)) {
+
+               m  = tmpsfi.code->m;
+               cl = class_get_classloader(m->clazz);
+
+               if (cl != NULL)
+                       return cl;
+       }
+
+       return NULL;
+}
+
+
 /* stacktrace_getClassContext **************************************************
 
    Creates a Class context array.
@@ -605,69 +811,79 @@ return_NULL:
 
 java_handle_objectarray_t *stacktrace_getClassContext(void)
 {
-       stacktracebuffer          *stb;
-       stacktrace_entry          *ste;
-       java_handle_objectarray_t *oa;
-       s4                         oalength;
-       s4                         i;
-       s4                         dumpsize;
+       stackframeinfo_t           *sfi;
+       stackframeinfo_t            tmpsfi;
+       int                         depth;
+       java_handle_objectarray_t  *oa;
+       java_object_t             **data;
+       int                         i;
+       methodinfo                 *m;
+
        CYCLES_STATS_DECLARE_AND_START
 
-       /* mark start of dump memory area */
+#if !defined(NDEBUG)
+       if (opt_DebugStackTrace)
+               log_println("[stacktrace_getClassContext]");
+#endif
 
-       dumpsize = dump_size();
+       sfi = threads_get_current_stackframeinfo();
 
-       /* create a stacktrace for the current thread */
+       /* Get the depth of the current stack. */
 
-       stb = stacktrace_create(STACKFRAMEINFO);
+       depth = stacktrace_depth(sfi);
 
-       if (stb == NULL)
-               goto return_NULL;
+       /* The first stackframe corresponds to the method whose
+          implementation calls this native function.  We remove that
+          entry. */
 
-       /* calculate the size of the Class array */
+       depth--;
+       stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
+       stacktrace_stackframeinfo_next(&tmpsfi);
 
-       for (i = 0, oalength = 0; i < stb->used; i++)
-               if (stb->entries[i].method != NULL)
-                       oalength++;
+       /* Allocate the Class array. */
 
-       /* The first entry corresponds to the method whose implementation */
-       /* calls stacktrace_getClassContext. We remove that entry.        */
+       oa = builtin_anewarray(depth, class_java_lang_Class);
 
-       ste = &(stb->entries[0]);
-       ste++;
-       oalength--;
+       if (oa == NULL) {
+               CYCLES_STATS_END(stacktrace_getClassContext);
 
-       /* allocate the Class array */
+               return NULL;
+       }
 
-       oa = builtin_anewarray(oalength, class_java_lang_Class);
-       if (!oa)
-               goto return_NULL;
+       /* Fill the Class array from the stacktrace list. */
 
-       /* fill the Class array from the stacktracebuffer */
+       LLNI_CRITICAL_START;
 
-       for(i = 0; i < oalength; i++, ste++) {
-               if (ste->method == NULL) {
-                       i--;
-                       continue;
-               }
+       data = LLNI_array_data(oa);
 
-               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->clazz;
+
+               i++;
+       }
+
+       LLNI_CRITICAL_END;
 
        CYCLES_STATS_END(stacktrace_getClassContext)
 
-       return NULL;
+       return oa;
 }
 
 
@@ -689,241 +905,410 @@ return_NULL:
 *******************************************************************************/
 
 #if defined(ENABLE_JAVASE)
-classinfo *stacktrace_getCurrentClass(void)
+classinfo *stacktrace_get_current_class(void)
 {
-       stacktracebuffer  *stb;
-       stacktrace_entry  *ste;
-       methodinfo        *m;
-       s4                 i;
-       s4                 dumpsize;
-       CYCLES_STATS_DECLARE_AND_START
+       stackframeinfo_t *sfi;
+       stackframeinfo_t  tmpsfi;
+       methodinfo       *m;
+
+       CYCLES_STATS_DECLARE_AND_START;
+
+#if !defined(NDEBUG)
+       if (opt_DebugStackTrace)
+               log_println("[stacktrace_get_current_class]");
+#endif
 
-       /* mark start of dump memory area */
+       /* Get the stackframeinfo of the current thread. */
 
-       dumpsize = dump_size();
+       sfi = threads_get_current_stackframeinfo();
 
-       /* create a stacktrace for the current thread */
+       /* If the stackframeinfo is NULL then FindClass is called through
+          the Invocation Interface and we return NULL */
 
-       stb = stacktrace_create(STACKFRAMEINFO);
+       if (sfi == NULL) {
+               CYCLES_STATS_END(stacktrace_getCurrentClass);
 
-       if (stb == NULL)
-               goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
+               return NULL;
+       }
 
-       /* iterate over all stacktrace entries and find the first suitable
-          class */
+       /* Iterate over the whole stack. */
 
-       for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
-               m = ste->method;
+       for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
+                stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
+                stacktrace_stackframeinfo_next(&tmpsfi)) {
+               /* Get the methodinfo. */
 
-               if (m == NULL)
-                       continue;
+               m = tmpsfi.code->m;
 
-               if (m->class == class_java_security_PrivilegedAction)
-                       goto return_NULL;
+               if (m->clazz == class_java_security_PrivilegedAction) {
+                       CYCLES_STATS_END(stacktrace_getCurrentClass);
 
-               if (m->class != NULL) {
-                       dump_release(dumpsize);
+                       return NULL;
+               }
 
-                       CYCLES_STATS_END(stacktrace_getCurrentClass)
+               if (m->clazz != NULL) {
+                       CYCLES_STATS_END(stacktrace_getCurrentClass);
 
-                       return m->class;
+                       return m->clazz;
                }
        }
 
-       /* 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 = threads_get_current_stackframeinfo();
 
-       if (stb == NULL)
-               goto return_NULL;
+       /* Get the depth of the current stack. */
 
-       /* get the first stacktrace entry */
+       depth = stacktrace_depth(sfi);
 
-       ste = &(stb->entries[0]);
+       if (depth == 0)
+               return NULL;
 
-       /* allocate all required arrays */
+       /* Allocate the required arrays. */
 
        oa = builtin_anewarray(2, arrayclass_java_lang_Object);
 
        if (oa == NULL)
                goto return_NULL;
 
-       classes = builtin_anewarray(stb->used, class_java_lang_Class);
+       classes = builtin_anewarray(depth, class_java_lang_Class);
 
        if (classes == NULL)
                goto return_NULL;
 
-       methodnames = builtin_anewarray(stb->used, class_java_lang_String);
+       methodnames = builtin_anewarray(depth, class_java_lang_String);
 
        if (methodnames == NULL)
                goto return_NULL;
 
-       /* set up the 2-dimensional array */
+       /* Set up the 2-dimensional array. */
 
        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;
+
+               /* Store the class in the array. */
+               /* NOTE: We use a LLNI-macro here, because a classinfo is not
+                  a handle. */
 
-       for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
-               c = ste->method->class;
+               LLNI_array_direct(classes, i) = (java_object_t *) m->clazz;
 
-               LLNI_array_direct(classes, i) = (java_object_t *) c;
+               /* Store the name in the array. */
 
-               string = javastring_new(ste->method->name);
+               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_entry ****************************************************
 
-/* stacktrace_print_trace_from_buffer ******************************************
+   Print line for a stacktrace entry.
 
-   Print the stacktrace of a given stacktracebuffer with CACAO intern
-   methods (no Java help). This method is used by
-   stacktrace_dump_trace and builtin_trace_exception.
+   ARGUMENTS:
+       m ............ methodinfo of the entry
+       linenumber ... linenumber of the entry
 
 *******************************************************************************/
 
-void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
+static void stacktrace_print_entry(methodinfo *m, int32_t linenumber)
 {
-       stacktrace_entry *ste;
-       methodinfo       *m;
-       s4                i;
+       /* Sanity check. */
 
-       ste = &(stb->entries[0]);
+       assert(m != NULL);
 
-       for (i = 0; i < stb->used; i++, ste++) {
-               m = ste->method;
+       printf("\tat ");
 
-               printf("\tat ");
-               utf_display_printable_ascii_classname(m->class->name);
-               printf(".");
-               utf_display_printable_ascii(m->name);
-               utf_display_printable_ascii(m->descriptor);
+       if (m->flags & ACC_METHOD_BUILTIN)
+               printf("NULL");
+       else
+               utf_display_printable_ascii_classname(m->clazz->name);
 
-               if (m->flags & ACC_NATIVE) {
-                       puts("(Native Method)");
+       printf(".");
+       utf_display_printable_ascii(m->name);
+       utf_display_printable_ascii(m->descriptor);
 
-               } else {
+       if (m->flags & ACC_NATIVE) {
+               puts("(Native Method)");
+       }
+       else {
+               if (m->flags & ACC_METHOD_BUILTIN) {
+                       puts("(builtin)");
+               }
+               else {
                        printf("(");
-                       utf_display_printable_ascii(m->class->sourcefile);
-                       printf(":%d)\n", (u4) ste->linenumber);
+                       utf_display_printable_ascii(m->clazz->sourcefile);
+                       printf(":%d)\n", linenumber);
                }
        }
 
-       /* just to be sure */
-
        fflush(stdout);
 }
 
 
-/* stacktrace_print_trace ******************************************************
+/* stacktrace_print ************************************************************
 
-   Print the stacktrace of a given exception. More or less a wrapper
-   to stacktrace_print_trace_from_buffer.
+   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(java_handle_t *xptr)
+void stacktrace_print(stacktrace_t *st)
 {
-       java_lang_Throwable     *t;
+       stacktrace_entry_t *ste;
+       methodinfo         *m;
+       int32_t             linenumber;
+       int                 i;
+
+       ste = &(st->entries[0]);
+
+       for (i = 0; i < st->length; i++, ste++) {
+               m = ste->code->m;
+
+               /* Get the line number. */
+
+               linenumber = linenumbertable_linenumber_for_pc(&m, ste->code, ste->pc);
+
+               stacktrace_print_entry(m, linenumber);
+       }
+}
+
+
+/* stacktrace_print_current ****************************************************
+
+   Print the current stacktrace of the current thread.
+
+   NOTE: This function prints all frames of the stacktrace and does
+   not skip frames like stacktrace_get.
+
+*******************************************************************************/
+
+void stacktrace_print_current(void)
+{
+       stackframeinfo_t *sfi;
+       stackframeinfo_t  tmpsfi;
+       codeinfo         *code;
+       methodinfo       *m;
+       int32_t           linenumber;
+
+       sfi = threads_get_current_stackframeinfo();
+
+       if (sfi == NULL) {
+               puts("\t<<No stacktrace available>>");
+               fflush(stdout);
+               return;
+       }
+
+       for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
+                stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
+                stacktrace_stackframeinfo_next(&tmpsfi)) {
+               /* Get the methodinfo. */
+
+               code = tmpsfi.code;
+               m    = code->m;
+
+               /* Get the line number. */
+
+               linenumber = linenumbertable_linenumber_for_pc(&m, code, tmpsfi.xpc);
+
+               stacktrace_print_entry(m, linenumber);
+       }
+}
+
+
+/* stacktrace_print_of_thread **************************************************
+
+   Print the current stacktrace of the given thread.
+
+   ARGUMENTS:
+       t ... thread
+
+*******************************************************************************/
+
+#if defined(ENABLE_THREADS)
+void stacktrace_print_of_thread(threadobject *t)
+{
+       stackframeinfo_t *sfi;
+       stackframeinfo_t  tmpsfi;
+       codeinfo         *code;
+       methodinfo       *m;
+       int32_t           linenumber;
+
+       /* Build a stacktrace for the passed thread. */
+
+       sfi = t->_stackframeinfo;
+       
+       if (sfi == NULL) {
+               puts("\t<<No stacktrace available>>");
+               fflush(stdout);
+               return;
+       }
+
+       for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
+                stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
+                stacktrace_stackframeinfo_next(&tmpsfi)) {
+               /* Get the methodinfo. */
+
+               code = tmpsfi.code;
+               m    = code->m;
+
+               /* Get the line number. */
+
+               linenumber = linenumbertable_linenumber_for_pc(&m, code, tmpsfi.xpc);
+
+               stacktrace_print_entry(m, linenumber);
+       }
+}
+#endif
+
+
+/* stacktrace_print_exception **************************************************
+
+   Print the stacktrace of a given exception (more or less a wrapper
+   to stacktrace_print).
+
+   IN:
+       h ... handle of exception to print
+
+*******************************************************************************/
+
+void stacktrace_print_exception(java_handle_t *h)
+{
+       java_lang_Throwable     *o;
+
 #if defined(WITH_CLASSPATH_GNU)
        java_lang_VMThrowable   *vmt;
 #endif
+
+       java_lang_Object        *backtrace;
        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