* src/vm/jit/linenumbertable.c: New file.
[cacao.git] / src / vm / jit / stacktrace.c
index e13c47d0844b9ef486cd6fa52937aac7d59a7f1b..b8847deb3ad31d9638d5ffd242b252900d2a8437 100644 (file)
@@ -56,6 +56,7 @@
 
 #include "toolbox/logging.h"
 
+#include "vm/array.h"
 #include "vm/builtin.h"
 #include "vm/cycles-stats.h"
 #include "vm/exceptions.h"
@@ -64,6 +65,7 @@
 
 #include "vm/jit/asmpart.h"
 #include "vm/jit/codegen-common.h"
+#include "vm/jit/linenumbertable.h"
 #include "vm/jit/methodheader.h"
 
 #include "vmcore/class.h"
@@ -73,7 +75,7 @@
 
 /* global variables ***********************************************************/
 #if !defined(ENABLE_THREADS)
-stackframeinfo *_no_threads_stackframeinfo = NULL;
+stackframeinfo_t *_no_threads_stackframeinfo = NULL;
 #endif
 
 CYCLES_STATS_DECLARE(stacktrace_overhead        ,100,1)
@@ -83,84 +85,22 @@ CYCLES_STATS_DECLARE(stacktrace_getCurrentClass ,40,5000)
 CYCLES_STATS_DECLARE(stacktrace_getStack        ,40,10000)
 
 
-/* stacktrace_create_stackframeinfo ********************************************
+/* stacktrace_stackframeinfo_add ***********************************************
 
-   Creates an stackframe info structure for inline code in the
-   interpreter.
+   Fills a stackframe info structure with the given or calculated
+   values and adds it to the chain.
 
 *******************************************************************************/
 
-#if defined(ENABLE_INTRP)
-void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv, u1 *sp,
-                                                                         u1 *ra)
-{
-       stackframeinfo **psfi;
-       methodinfo      *m;
-       codeinfo        *code;
-
-       /* get current stackframe info pointer */
-
-       psfi = &STACKFRAMEINFO;
-
-       /* if we don't have pv handy */
-
-       if (pv == NULL) {
-#if defined(ENABLE_INTRP)
-               if (opt_intrp)
-                       pv = codegen_get_pv_from_pc(ra);
-               else
-#endif
-                       {
-#if defined(ENABLE_JIT)
-                               pv = md_codegen_get_pv_from_pc(ra);
-#endif
-                       }
-       }
-
-       /* get codeinfo pointer from data segment */
-
-       code = *((codeinfo **) (pv + CodeinfoPointer));
-
-       /* For asm_vm_call_method the codeinfo pointer is NULL. */
-
-       m = (code == NULL) ? NULL : code->m;
-
-       /* fill new stackframe info structure */
-
-       sfi->prev   = *psfi;
-       sfi->method = m;
-       sfi->pv     = pv;
-       sfi->sp     = sp;
-       sfi->ra     = ra;
-
-       /* xpc is the same as ra, but is required in stacktrace_create */
-
-       sfi->xpc    = ra;
-
-       /* store new stackframe info pointer */
-
-       *psfi = sfi;
-}
-#endif /* defined(ENABLE_INTRP) */
-
-
-/* stacktrace_create_extern_stackframeinfo *************************************
-
-   Creates an stackframe info structure for an extern exception
-   (hardware or assembler).
-
-*******************************************************************************/
-
-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;
-       methodinfo      *m;
+       stackframeinfo_t **psfi;
+       codeinfo          *code;
 #if !defined(__I386__) && !defined(__X86_64__) && !defined(__S390__) && !defined(__M68K__)
-       bool             isleafmethod;
+       bool               isleafmethod;
 #endif
 #if defined(ENABLE_JIT)
-       s4               framesize;
+       s4                 framesize;
 #endif
 
        /* get current stackframe info pointer */
@@ -187,9 +127,9 @@ void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
                        }
        }
 
-       /* 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); */
@@ -240,12 +180,23 @@ void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
 
        /* Fill new stackframeinfo structure. */
 
-       sfi->prev   = *psfi;
-       sfi->method = m;
-       sfi->pv     = pv;
-       sfi->sp     = sp;
-       sfi->ra     = ra;
-       sfi->xpc    = xpc;
+       sfi->prev = *psfi;
+       sfi->code = code;
+       sfi->pv   = pv;
+       sfi->sp   = sp;
+       sfi->ra   = ra;
+       sfi->xpc  = xpc;
+
+#if !defined(NDEBUG)
+       if (opt_DebugStackFrameInfo) {
+               log_start();
+               log_print("[stackframeinfo add   : sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
+                                 sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
+               method_print(sfi->code->m);
+               log_print("]");
+               log_finish();
+       }
+#endif
 
        /* Store new stackframeinfo pointer. */
 
@@ -259,15 +210,16 @@ void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
 }
 
 
-/* stacktrace_remove_stackframeinfo ********************************************
+/* stacktrace_stackframeinfo_remove ********************************************
 
-   Remove the topmost stackframeinfo in the current thread.
+   Remove the given stackframeinfo from the chain in the current
+   thread.
 
 *******************************************************************************/
 
-void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
+void stacktrace_stackframeinfo_remove(stackframeinfo_t *sfi)
 {
-       stackframeinfo **psfi;
+       stackframeinfo_t **psfi;
 
        /* clear the native world flag for the current thread */
        /* ATTENTION: Clear this flag _before_ removing the stackframe info */
@@ -278,6 +230,17 @@ void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
 
        psfi = &STACKFRAMEINFO;
 
+#if !defined(NDEBUG)
+       if (opt_DebugStackFrameInfo) {
+               log_start();
+               log_print("[stackframeinfo remove: sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
+                                 sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
+               method_print(sfi->code->m);
+               log_print("]");
+               log_finish();
+       }
+#endif
+
        /* restore the old pointer */
 
        *psfi = sfi->prev;
@@ -348,18 +311,21 @@ static inline stacktracebuffer *stacktrace_entry_add(stacktracebuffer *stb, meth
 
 *******************************************************************************/
 
-static inline stacktracebuffer *stacktrace_method_add(stacktracebuffer *stb, stackframeinfo *sfi)
+static inline stacktracebuffer *stacktrace_method_add(stacktracebuffer *stb, stackframeinfo_t *sfi)
 {
-       methodinfo *m;
+       codeinfo   *code;
        void       *pv;
        void       *xpc;
+       methodinfo *m;
        int32_t     linenumber;
 
        /* Get values from the stackframeinfo. */
 
-       m   = sfi->method;
-       pv  = sfi->pv;
-       xpc = sfi->xpc;
+       code = sfi->code;
+       pv   = sfi->pv;
+       xpc  = sfi->xpc;
+
+       m = code->m;
 
        /* Skip builtin methods. */
 
@@ -368,7 +334,7 @@ static inline stacktracebuffer *stacktrace_method_add(stacktracebuffer *stb, sta
 
        /* Search the line number table. */
 
-       linenumber = dseg_get_linenumber_from_pc(&m, pv, xpc);
+       linenumber = linenumbertable_linenumber_for_pc(&m, code, xpc);
 
        /* Add a new entry to the staktrace. */
 
@@ -383,33 +349,40 @@ static inline stacktracebuffer *stacktrace_method_add(stacktracebuffer *stb, sta
    Walk the stack (or the stackframeinfo-chain) to the next method.
 
    IN:
-       sfi....stackframeinfo of current method
+       tmpsfi ... stackframeinfo of current method
+
+   RETURN:
+       true .... the sfi is filled with the new values
+       false ... we reached the top of the stacktrace
 
 *******************************************************************************/
 
-static inline void stacktrace_stack_walk(stackframeinfo *sfi)
+static inline bool stacktrace_stack_walk(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. */
 
-       m   = sfi->method;
-       pv  sfi->pv;
-       sp  sfi->sp;
-       ra  sfi->ra;
-       xpc sfi->xpc;
+       code = tmpsfi->code;
+       pv   = tmpsfi->pv;
+       sp   = tmpsfi->sp;
+       ra   = tmpsfi->ra;
+       xpc  = tmpsfi->xpc;
 
        /* Get the current stack frame size. */
 
        framesize = *((uint32_t *) (((intptr_t) pv) + FrameSize));
 
        /* 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)
@@ -417,7 +390,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
@@ -440,9 +416,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. */
 
@@ -461,15 +437,46 @@ 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;
 
-       sfi->method = m;
-       sfi->pv     = pv;
-       sfi->sp     = sp;
-       sfi->ra     = ra;
-       sfi->xpc    = (void *) (((intptr_t) ra) - 1);
+               /* If the previous stackframeinfo in the chain is NULL we
+                  reached the top of the stacktrace and return false. */
+
+               if (prevsfi == NULL)
+                       return false;
+
+               /* Fill the temporary stackframeinfo with the new values. */
+
+               tmpsfi->code = prevsfi->code;
+               tmpsfi->pv   = prevsfi->pv;
+               tmpsfi->sp   = prevsfi->sp;
+               tmpsfi->ra   = prevsfi->ra;
+               tmpsfi->xpc  = prevsfi->xpc;
+
+               /* Set the previous stackframe info of the temporary one to
+                  the next in the chain. */
+
+               tmpsfi->prev = prevsfi->prev;
+       }
+       else {
+               /* Store the new values in the stackframeinfo.  NOTE: We
+                  subtract 1 from the RA to get the XPC, because the RA
+                  points to the instruction after the call instruction. */
+
+               tmpsfi->code = code;
+               tmpsfi->pv   = pv;
+               tmpsfi->sp   = sp;
+               tmpsfi->ra   = ra;
+               tmpsfi->xpc  = (void *) (((intptr_t) ra) - 1);
+       }
+
+       return true;
 }
 
 
@@ -490,10 +497,15 @@ static inline void stacktrace_stack_walk(stackframeinfo *sfi)
 
 *******************************************************************************/
 
-stacktracebuffer *stacktrace_create(stackframeinfo *sfi)
+stacktracebuffer *stacktrace_create(stackframeinfo_t *sfi)
 {
        stacktracebuffer *stb;
-       stackframeinfo    tmpsfi;
+       stackframeinfo_t  tmpsfi;
+       bool              skip_fillInStackTrace;
+       bool              skip_init;
+
+       skip_fillInStackTrace = true;
+       skip_init             = true;
 
        /* Create a stacktracebuffer in dump memory. */
 
@@ -517,68 +529,78 @@ stacktracebuffer *stacktrace_create(stackframeinfo *sfi)
        if (sfi == NULL)
                return NULL;
 
-       tmpsfi.method = sfi->method;
-       tmpsfi.pv     = sfi->pv;
-       tmpsfi.sp     = sfi->sp;
-       tmpsfi.ra     = sfi->ra;
-       tmpsfi.xpc    = sfi->xpc;
+       tmpsfi.code = sfi->code;
+       tmpsfi.pv   = sfi->pv;
+       tmpsfi.sp   = sfi->sp;
+       tmpsfi.ra   = sfi->ra;
+       tmpsfi.xpc  = sfi->xpc;
+
+       /* Initially set the previous stackframe info of the temporary one
+          to the next in the chain. */
+
+       tmpsfi.prev = sfi->prev;
 
        /* Iterate till we're done. */
 
-       for (;;) {
+       do {
 #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.code->m, tmpsfi.pv, tmpsfi.sp, tmpsfi.ra,
                                          tmpsfi.xpc);
-                       method_print(tmpsfi.method);
+                       method_print(tmpsfi.code->m);
                        log_print("]");
                        log_finish();
                }
 #endif
 
-               /* Check for Throwable.fillInStackTrace(). */
+               /* This logic is taken from
+                  hotspot/src/share/vm/classfile/javaClasses.cpp
+                  (java_lang_Throwable::fill_in_stack_trace). */
 
-/*             if (tmpsfi.method->name != utf_fillInStackTrace) { */
-                       
-                       /* Add this method to the stacktrace. */
+               if (skip_fillInStackTrace == true) {
+                       /* Check "fillInStackTrace" only once, so we negate the
+                          flag after the first time check. */
 
-                       stb = stacktrace_method_add(stb, &tmpsfi);
-/*             } */
+#if defined(WITH_CLASSPATH_GNU)
+                       /* For GNU Classpath we also need to skip
+                          VMThrowable.fillInStackTrace(). */
 
-               /* Walk the stack (or the stackframeinfo chain) and get the
-                  next method. */
+                       if ((tmpsfi.code->m->class == class_java_lang_VMThrowable) &&
+                               (tmpsfi.code->m->name  == utf_fillInStackTrace))
+                               continue;
+#endif
 
-               stacktrace_stack_walk(&tmpsfi);
+                       skip_fillInStackTrace = false;
 
-               /* 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. */
+                       if (tmpsfi.code->m->name == utf_fillInStackTrace)
+                               continue;
+               }
 
-               if (tmpsfi.method == NULL) {
-                       sfi = sfi->prev;
+               /* 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 the previous stackframeinfo in the chain is NULL we
-                          reached the top of the stacktrace and leave the
-                          loop. */
+               if (skip_init == true) {
+                       if (tmpsfi.code->m->name == utf_init) {
+/*                             throwable->is_a(method->method_holder())) { */
+                               continue;
+                       }
+                       else {
+                               /* If no "Throwable.init()" method found, we stop
+                                  checking it next time. */
 
-                       if (sfi == NULL)
-                               break;
+                               skip_init = false;
+                       }
+               }
 
-                       /* Fill the temporary stackframeinfo with the new
-                          values. */
+               /* Add this method to the stacktrace. */
 
-                       tmpsfi.method = sfi->method;
-                       tmpsfi.pv     = sfi->pv;
-                       tmpsfi.sp     = sfi->sp;
-                       tmpsfi.ra     = sfi->ra;
-                       tmpsfi.xpc    = sfi->xpc;
-               }
-       }
+               stb = stacktrace_method_add(stb, &tmpsfi);
+       } while (stacktrace_stack_walk(&tmpsfi) == true);
 
 #if !defined(NDEBUG)
        if (opt_DebugStackTrace) {
@@ -860,8 +882,8 @@ java_handle_objectarray_t *stacktrace_getStack(void)
 
        /* set up the 2-dimensional array */
 
-       LLNI_objectarray_element_set(oa, 0, classes);
-       LLNI_objectarray_element_set(oa, 1, 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 */
 
@@ -875,7 +897,7 @@ java_handle_objectarray_t *stacktrace_getStack(void)
                if (string == NULL)
                        goto return_NULL;
 
-               LLNI_objectarray_element_set(methodnames, i, string);
+               array_objectarray_element_set(methodnames, i, string);
        }
 
        /* return the 2-dimensional array */