Merged with tip.
[cacao.git] / src / vm / jit / stacktrace.c
index 2eaa5089a449428b6a7177e873d2f5a5b114751f..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.
 
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   $Id: stacktrace.c 8318 2007-08-16 10:05:34Z michi $
-
 */
 
 
 #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
 
-#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/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 "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)
-
-
-/* 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 */
+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)
 
-       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 */
+/* stacktrace_stackframeinfo_add ***********************************************
 
-       sfi->xpc    = ra;
-
-       /* store new stackframe info pointer */
-
-       *psfi = sfi;
-}
-#endif /* defined(ENABLE_INTRP) */
-
-
-/* stacktrace_create_extern_stackframeinfo *************************************
-
-   Creates an stackframe info structure for an extern exception
-   (hardware or assembler).
+   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__) && !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). */
@@ -173,7 +109,7 @@ void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
        if (pv == NULL) {
 #if defined(ENABLE_INTRP)
                if (opt_intrp)
-                       pv = codegen_get_pv_from_pc(ra);
+                       pv = methodtree_find(ra);
                else
 #endif
                        {
@@ -187,6 +123,13 @@ void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
                        }
        }
 
+       /* 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. */
@@ -204,14 +147,13 @@ void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
 
                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. */
+               /* 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. */
 
-               isleafmethod = *((s4 *) (pv + IsLeaf));
-
-               if (!isleafmethod) {
+               if ((code == NULL) || !code_is_leafmethod(code)) {
                        framesize = *((u4 *) (pv + FrameSize));
 
                        ra = md_stacktrace_get_returnaddress(sp, framesize);
@@ -220,505 +162,638 @@ void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
 # if defined(ENABLE_INTRP)
        }
 # endif
-#endif /* defined(ENABLE_JIT) */
+#endif
+
+       /* 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. */
+
+       if (xpc == NULL) {
+               xpc = (void *) (((intptr_t) ra) - 1);
+       }
+
+       /* Fill new stackframeinfo structure. */
+
+       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
 
-       /* fill new stackframe info structure */
+       /* Store new stackframeinfo pointer. */
 
-       sfi->prev   = *psfi;
-       sfi->method = NULL;
-       sfi->pv     = pv;
-       sfi->sp     = sp;
-       sfi->ra     = ra;
-       sfi->xpc    = xpc;
+       threads_set_current_stackframeinfo(sfi);
 
-       /* store new stackframe info pointer */
+       /* 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. */
 
-       *psfi = sfi;
+       THREAD_NATIVEWORLD_ENTER;
 }
 
 
-/* stacktrace_create_native_stackframeinfo *************************************
+/* stacktrace_stackframeinfo_remove ********************************************
 
-   Creates a stackframe info structure for a native stub.
+   Remove the given stackframeinfo from the chain in the current
+   thread.
 
 *******************************************************************************/
 
-void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv,
-                                                                                        u1 *sp, u1 *ra)
+void stacktrace_stackframeinfo_remove(stackframeinfo_t *sfi)
 {
-       stackframeinfo **psfi;
-       methodinfo      *m;
-       codeinfo        *code;
+       /* Clear the native world flag for the current thread. */
+       /* ATTENTION: Clear this flag _before_ removing the stackframe info. */
+
+       THREAD_NATIVEWORLD_EXIT;
+
+#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
 
-       /* get codeinfo pointer from data segment */
+       /* Set previous stackframe info. */
 
-       code = *((codeinfo **) (pv + CodeinfoPointer));
+       threads_set_current_stackframeinfo(sfi->prev);
+}
 
-       /* For asm_vm_call_method the codeinfo pointer is NULL. */
 
-       m = (code == NULL) ? NULL : code->m;
+/* stacktrace_stackframeinfo_fill **********************************************
 
-       /* get current stackframe info pointer */
+   Fill the temporary stackframeinfo structure with the values given
+   in sfi.
 
-       psfi = &STACKFRAMEINFO;
+   IN:
+       tmpsfi ... temporary stackframeinfo
+       sfi ...... stackframeinfo to be used in the next iteration
 
-       /* fill new stackframe info structure */
+*******************************************************************************/
+
+static inline void stacktrace_stackframeinfo_fill(stackframeinfo_t *tmpsfi, stackframeinfo_t *sfi)
+{
+       /* Sanity checks. */
+
+       assert(tmpsfi != NULL);
+       assert(sfi != NULL);
+
+       /* Fill the temporary stackframeinfo. */
+
+       tmpsfi->code = sfi->code;
+       tmpsfi->pv   = sfi->pv;
+       tmpsfi->sp   = sfi->sp;
+       tmpsfi->ra   = sfi->ra;
+       tmpsfi->xpc  = sfi->xpc;
 
-       sfi->prev   = *psfi;
-       sfi->method = m;
-       sfi->pv     = NULL;
-       sfi->sp     = sp;
-       sfi->ra     = ra;
-       sfi->xpc    = NULL;
+       /* Set the previous stackframe info of the temporary one to the
+          next in the chain. */
 
-       /* store new stackframe info pointer */
+       tmpsfi->prev = sfi->prev;
 
-       *psfi = sfi;
+#if !defined(NDEBUG)
+       if (opt_DebugStackTrace)
+               log_println("[stacktrace fill]");
+#endif
 }
 
 
-/* stacktrace_remove_stackframeinfo ********************************************
+/* 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.
 
-   Remove the topmost stackframeinfo in the current thread.
+   ATTENTION: This function does NOT skip builtin methods!
+
+   IN:
+       tmpsfi ... temporary stackframeinfo of current method
 
 *******************************************************************************/
 
-void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
+static inline void stacktrace_stackframeinfo_next(stackframeinfo_t *tmpsfi)
 {
-       stackframeinfo **psfi;
+       codeinfo         *code;
+       void             *pv;
+       void             *sp;
+       void             *ra;
+       void             *xpc;
+       uint32_t          framesize;
+       stackframeinfo_t *prevsfi;
 
-       /* get current stackframe info pointer */
+       /* Sanity check. */
 
-       psfi = &STACKFRAMEINFO;
+       assert(tmpsfi != NULL);
 
-       /* restore the old pointer */
+       /* Get values from the stackframeinfo. */
 
-       *psfi = sfi->prev;
-}
+       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));
 
-/* stacktrace_add_entry ********************************************************
+       /* 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). */
 
-   Adds a new entry to the stacktrace buffer.
+#if defined(ENABLE_JIT)
+# if defined(ENABLE_INTRP)
+       if (opt_intrp)
+               ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
+       else
+# endif
+               {
+                       if (!code_is_leafmethod(code))
+                               ra = md_stacktrace_get_returnaddress(sp, framesize);
+               }
+#else
+       ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
+#endif
 
-*******************************************************************************/
+       /* Get the PV for the parent Java method. */
 
-static void stacktrace_add_entry(stacktracebuffer *stb, methodinfo *m, u2 line)
-{
-       stacktrace_entry *ste;
+#if defined(ENABLE_INTRP)
+       if (opt_intrp)
+               pv = methodtree_find(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
+               }
+
+       /* Get the codeinfo pointer for the parent Java method. */
 
-       /* check if we already reached the buffer capacity */
+       code = code_get_codeinfo_for_pv(pv);
 
-       if (stb->used >= stb->capacity) {
-               /* reallocate new memory */
+       /* Calculate the SP for the parent Java method. */
 
-               stb->entries = DMREALLOC(stb->entries, stacktrace_entry, stb->capacity,
-                                                                stb->capacity + STACKTRACE_CAPACITY_INCREMENT);
+#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
+               }
 
-               /* set new buffer capacity */
+       /* 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. */
 
-               stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
-       }
+       if (code == NULL) {
+               prevsfi = tmpsfi->prev;
 
-       /* insert the current entry */
+               /* 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. */
 
-       ste = &(stb->entries[stb->used]);
+               if (prevsfi == NULL) {
+                       tmpsfi->code = NULL;
+                       tmpsfi->prev = NULL;
+                       return;
+               }
 
-       ste->method     = m;
-       ste->linenumber = line;
+               /* Fill the temporary stackframeinfo with the new values. */
 
-       /* increase entries used count */
+               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);
+       }
 
-       stb->used += 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_add_method *******************************************************
+/* stacktrace_stackframeinfo_end_check *****************************************
 
-   Add stacktrace entries[1] for the given method to the stacktrace buffer.
+   Check if we reached the end of the 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
+       tmpsfi ... temporary stackframeinfo of current method
 
-   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)
+   RETURN:
+       true .... the end is reached
+          false ... the end is not reached
 
 *******************************************************************************/
 
-static bool stacktrace_add_method(stacktracebuffer *stb, methodinfo *m, u1 *pv,
-                                                                 u1 *pc)
+static inline bool stacktrace_stackframeinfo_end_check(stackframeinfo_t *tmpsfi)
 {
-       codeinfo *code;                     /* compiled realization of method     */
-       s4        linenumber;
-
-       /* find the realization of the method the pc is in */
-
-       code = *((codeinfo **) (pv + CodeinfoPointer));
+       /* Sanity check. */
 
-       /* search the line number table */
+       assert(tmpsfi != NULL);
 
-       linenumber = dseg_get_linenumber_from_pc(&m, pv, pc);
-
-       /* now add a new entry to the staktrace */
+       if ((tmpsfi->code == NULL) && (tmpsfi->prev == NULL)) {
+#if !defined(NDEBUG)
+               if (opt_DebugStackTrace)
+                       log_println("[stacktrace stop]");
+#endif
 
-       stacktrace_add_entry(stb, m, linenumber);
+               return true;
+       }
 
-       return true;
+       return false;
 }
 
 
-/* stacktrace_create ***********************************************************
+/* stacktrace_depth ************************************************************
 
-   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).
+   Calculates and returns the depth of the current stacktrace.
 
-   RETURN VALUE:
-      pointer to the stacktracebuffer, or
-      NULL if there is no stacktrace available for the
-      given thread.
+   IN:
+       sfi ... stackframeinfo where to start the stacktrace
+
+   RETURN:
+       depth of the stacktrace
 
 *******************************************************************************/
 
-stacktracebuffer *stacktrace_create(stackframeinfo *sfi)
+static int stacktrace_depth(stackframeinfo_t *sfi)
 {
-       stacktracebuffer *stb;
+       stackframeinfo_t  tmpsfi;
+       int               depth;
        methodinfo       *m;
-       codeinfo         *code;
-       u1               *pv;
-       u1               *sp;
-       u4                framesize;
-       u1               *ra;
-       u1               *xpc;
-
-       /* prevent compiler warnings */
 
-       pv = NULL;
-       sp = NULL;
-       ra = NULL;
+#if !defined(NDEBUG)
+       if (opt_DebugStackTrace)
+               log_println("[stacktrace_depth]");
+#endif
 
-       /* create a stacktracebuffer in dump memory */
+       /* XXX This is not correct, but a workaround for threads-dump for
+          now. */
+/*     assert(sfi != NULL); */
+       if (sfi == NULL)
+               return 0;
 
-       stb = DNEW(stacktracebuffer);
+       /* Iterate over all stackframes. */
 
-       stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
-       stb->used     = 0;
-       stb->entries  = DMNEW(stacktrace_entry, STACKTRACE_CAPACITY_DEFAULT);
+       depth = 0;
 
-#define PRINTMETHODS 0
+       for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
+                stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
+                stacktrace_stackframeinfo_next(&tmpsfi)) {
+               /* Get methodinfo. */
 
-#if PRINTMETHODS
-       printf("\n\nfillInStackTrace start:\n");
-       fflush(stdout);
-#endif
+               m = tmpsfi.code->m;
 
-       /* Loop while we have a method pointer (asm_calljavafunction has
-          NULL) or there is a stackframeinfo in the chain. */
+               /* Skip builtin methods. */
 
-       m = NULL;
+               if (m->flags & ACC_METHOD_BUILTIN)
+                       continue;
 
-       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. */
+               depth++;
+       }
 
-               if (m == NULL) {
-                       /* for native stub stackframe infos, pv is always NULL */
+       return depth;
+}
 
-                       if (sfi->pv == NULL) {
-                               /* get methodinfo, sp and ra from the current stackframe info */
 
-                               m  = sfi->method;
-                               sp = sfi->sp;           /* sp of parent Java function         */
-                               ra = sfi->ra;
+/* stacktrace_get **************************************************************
 
-                               if (m)
-                                       stacktrace_add_entry(stb, m, 0);
+   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.
 
-#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*). */
+   IN:
+       sfi ... stackframe info to start stacktrace from
 
-#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
-                                       }
+   RETURN:
+       stacktrace as Java byte-array
 
-                               /* get methodinfo pointer from parent data segment */
+*******************************************************************************/
 
-                               code = *((codeinfo **) (pv + CodeinfoPointer));
+java_handle_bytearray_t *stacktrace_get(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;
 
-                               /* For asm_vm_call_method the codeinfo pointer is
-                                  NULL. */
+       CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
 
-                               m = (code == NULL) ? NULL : code->m;
+#if !defined(NDEBUG)
+       if (opt_DebugStackTrace)
+               log_println("[stacktrace_get]");
+#endif
 
-                       } else {
-                               /* Inline stackframe infos are special: they have a
-                                  xpc of the actual exception position and the return
-                                  address saved since an inline stackframe info can
-                                  also be in a leaf method (no return address saved
-                                  on stack!!!).  ATTENTION: This one is also for
-                                  hardware exceptions!!! */
+       skip_fillInStackTrace = true;
+       skip_init             = true;
 
-                               /* get methodinfo, sp and ra from the current stackframe info */
+       depth = stacktrace_depth(sfi);
 
-                               m   = sfi->method;      /* m == NULL                          */
-                               pv  = sfi->pv;          /* pv of parent Java function         */
-                               sp  = sfi->sp;          /* sp of parent Java function         */
-                               ra  = sfi->ra;          /* ra of parent Java function         */
-                               xpc = sfi->xpc;         /* actual exception position          */
+       if (depth == 0)
+               return NULL;
 
-#if PRINTMETHODS
-                               printf("ra=%p sp=%p, ", ra, sp);
-                               printf("NULL: inline stub\n");
-                               fflush(stdout);
-#endif
+       /* 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. */
 
-                               /* 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__) || defined (__M68K__)
-                                       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->clazz == 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) &&
+                               (class_issubclass(m->clazz, class_java_lang_Throwable))) {
+                               continue;
                        }
+                       else {
+                               /* If no "Throwable.init()" method found, we stop
+                                  checking it next time. */
 
-                       /* get previous stackframeinfo in the chain */
+                               skip_init = false;
+                       }
+               }
 
-                       sfi = sfi->prev;
+               /* Store the stacktrace entry and increment the pointer. */
 
-               } else {
-#if PRINTMETHODS
-                       printf("ra=%p sp=%p, ", ra, sp);
-                       method_print(m);
-                       printf(": JIT");
-                       fflush(stdout);
-#endif
+               ste->code = tmpsfi.code;
+               ste->pc   = tmpsfi.xpc;
 
-                       /* JIT method found, add it to the stacktrace (we subtract
-                          1 from the return address since it points the the
-                          instruction after call). */
+               ste++;
+       }
 
-                       stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1);
+       /* Store the number of entries in the stacktrace structure. */
 
-                       /* get the current stack frame size */
+       st->length = ste - st->entries;
 
-                       framesize = *((u4 *) (pv + FrameSize));
+       LLNI_CRITICAL_END;
 
-#if PRINTMETHODS
-                       printf(", framesize=%d\n", framesize);
-                       fflush(stdout);
-#endif
+       /* release dump memory */
 
-                       /* get return address of current stack frame */
+/*     dump_release(dumpsize); */
 
-#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
+       CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
+                                                                  stacktrace_overhead)
+       return ba;
 
-                       /* get data segment and methodinfo pointer from parent method */
+return_NULL:
+/*     dump_release(dumpsize); */
 
-#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
-                               }
+       CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
+                                                                  stacktrace_overhead)
 
-                       code = *((codeinfo **) (pv + CodeinfoPointer));
+       return NULL;
+}
 
-                       /* For asm_vm_call_method the codeinfo pointer is NULL. */
 
-                       m = (code == NULL) ? NULL : code->m;
+/* stacktrace_get_current ******************************************************
 
-                       /* walk the stack */
+   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.
 
-#if defined(ENABLE_INTRP)
-                       if (opt_intrp)
-                               sp = *(u1 **) (sp - framesize);
-                       else
-#endif
-                               {
-#if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
-                                       sp += framesize + SIZEOF_VOID_P;
-#elif defined(__SPARC_64__)
-                                       /* already has the new sp */
-#else
-                                       sp += framesize;
-#endif
-                               }
-               }
-       }
+   RETURN:
+       stacktrace as Java byte-array
 
-       /* return the stacktracebuffer */
+*******************************************************************************/
 
-       if (stb->used == 0)
-               return NULL;
-       else
-               return stb;
+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_fillInStackTrace *************************************************
+/* stacktrace_get_caller_class *************************************************
 
-   Generate a stacktrace from the current thread for
-   java.lang.VMThrowable.fillInStackTrace.
+   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
 
 *******************************************************************************/
 
-stacktracecontainer *stacktrace_fillInStackTrace(void)
+#if defined(ENABLE_JAVASE)
+classinfo *stacktrace_get_caller_class(int depth)
 {
-       stacktracebuffer    *stb;
-       stacktracecontainer *gcstc;
-       s4                   gcstc_size;
-       s4                   dumpsize;
-       CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
+       stackframeinfo_t *sfi;
+       stackframeinfo_t  tmpsfi;
+       methodinfo       *m;
+       classinfo        *c;
+       int               i;
 
-       /* mark start of dump memory area */
+#if !defined(NDEBUG)
+       if (opt_DebugStackTrace)
+               log_println("[stacktrace_get_caller_class]");
+#endif
 
-       dumpsize = dump_size();
+       /* Get the stackframeinfo of the current thread. */
 
-       /* create a stacktrace from the current thread */
+       sfi = threads_get_current_stackframeinfo();
 
-       stb = stacktrace_create(STACKFRAMEINFO);
+       /* Iterate over the whole stack until we reached the requested
+          depth. */
 
-       if (stb == NULL)
-               goto return_NULL;
+       i = 0;
 
-       /* allocate memory from the GC heap and copy the stacktrace buffer */
-       /* ATTENTION: use stacktracecontainer for this and make it look like
-       an array */
+       for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
+                stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
+                stacktrace_stackframeinfo_next(&tmpsfi)) {
 
-       gcstc_size = sizeof(stacktracebuffer) +
-                    sizeof(stacktrace_entry) * stb->used;
-       gcstc = (stacktracecontainer *) builtin_newarray_byte(gcstc_size);
+               m = tmpsfi.code->m;
+               c = m->clazz;
 
-       if (gcstc == NULL)
-               goto return_NULL;
+               /* Skip builtin methods. */
 
-       gcstc->stb.capacity = stb->capacity;
-       gcstc->stb.used     = stb->used;
-       gcstc->stb.entries  = gcstc->data;
+               if (m->flags & ACC_METHOD_BUILTIN)
+                       continue;
 
-       MCOPY(gcstc->data, stb->entries, stacktrace_entry, stb->used);
+#if defined(WITH_CLASSPATH_SUN)
+               /* NOTE: See hotspot/src/share/vm/runtime/vframe.cpp
+                  (vframeStreamCommon::security_get_caller_frame). */
 
-       /* release dump memory */
+               /* This is java.lang.reflect.Method.invoke(), skip it. */
 
-       dump_release(dumpsize);
+               if (m == method_java_lang_reflect_Method_invoke)
+                       continue;
 
-       CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
-                                                                  stacktrace_overhead)
-       return gcstc;
+               /* This is an auxiliary frame, skip it. */
 
-return_NULL:
-       dump_release(dumpsize);
+               if (class_issubclass(c, class_sun_reflect_MagicAccessorImpl))
+                       continue;
+#endif
 
-       CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
-                                                                  stacktrace_overhead)
+               /* 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;
 }
@@ -736,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);
 
-               oa->data[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;
 }
 
 
@@ -820,240 +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;
 
-       /* 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 = threads_get_current_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->clazz == class_java_security_PrivilegedAction) {
+                       CYCLES_STATS_END(stacktrace_getCurrentClass);
 
-                       return m->class;
+                       return NULL;
                }
-       }
 
-       /* no Java method found on the stack */
+               if (m->clazz != NULL) {
+                       CYCLES_STATS_END(stacktrace_getCurrentClass);
 
-return_NULL:
-       dump_release(dumpsize);
+                       return m->clazz;
+               }
+       }
+
+       /* 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. */
 
-       oa->data[0] = (java_object_t *) classes;
-       oa->data[1] = (java_object_t *) methodnames;
+       array_objectarray_element_set(oa, 0, (java_handle_t *) classes);
+       array_objectarray_element_set(oa, 1, (java_handle_t *) methodnames);
 
-       /* iterate over all stacktrace entries */
+       /* Iterate over the whole stack. */
+       /* TODO We should use a critical section here to speed things
+          up. */
 
-       for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
-               c = ste->method->class;
+       i = 0;
 
-               classes->data[i] = (java_object_t *) c;
+       for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
+                stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
+                stacktrace_stackframeinfo_next(&tmpsfi)) {
+               /* Get the methodinfo. */
 
-               string = javastring_new(ste->method->name);
+               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. */
+
+               LLNI_array_direct(classes, i) = (java_object_t *) m->clazz;
+
+               /* 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_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 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(stacktrace_t *st)
+{
+       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.
 
-   Print the stacktrace of a given exception. More or less a wrapper
-   to stacktrace_print_trace_from_buffer.
+   NOTE: This function prints all frames of the stacktrace and does
+   not skip frames like stacktrace_get.
 
 *******************************************************************************/
 
-void stacktrace_print_trace(java_handle_t *xptr)
+void stacktrace_print_current(void)
 {
-       java_lang_Throwable   *t;
+       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;
+       java_lang_VMThrowable   *vmt;
 #endif
-       stacktracecontainer   *stc;
-       stacktracebuffer      *stb;
 
-       t = (java_lang_Throwable *) xptr;
+       java_lang_Object        *backtrace;
+       java_handle_bytearray_t *ba;
+       stacktrace_t            *st;
+
+       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);
-       stc = (stacktracecontainer *) LLNI_field_direct(vmt, vmData);
+
+       LLNI_field_get_ref(o,   vmState, vmt);
+       LLNI_field_get_ref(vmt, vmdata,  backtrace);
+
 #elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
-       stc = (stacktracecontainer *) t->backtrace;
+
+       LLNI_field_get_ref(o, backtrace, backtrace);
+
 #else
 # error unknown classpath configuration
 #endif
 
-       stb = &(stc->stb);
+       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