Merged with tip.
[cacao.git] / src / vm / jit / stacktrace.c
index e8d59d422a513669569c4c0aa59304362eb4cdbd..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.
 
 #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/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_t *_no_threads_stackframeinfo = NULL;
-#endif
 
 CYCLES_STATS_DECLARE(stacktrace_overhead        , 100, 1)
 CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace, 40,  5000)
@@ -97,18 +93,15 @@ CYCLES_STATS_DECLARE(stacktrace_get_stack       , 40,  10000)
 
 void stacktrace_stackframeinfo_add(stackframeinfo_t *sfi, u1 *pv, u1 *sp, u1 *ra, u1 *xpc)
 {
-       stackframeinfo_t **psfi;
-       codeinfo          *code;
-#if !defined(__I386__) && !defined(__X86_64__) && !defined(__S390__) && !defined(__M68K__)
-       bool               isleafmethod;
-#endif
+       stackframeinfo_t *currentsfi;
+       codeinfo         *code;
 #if defined(ENABLE_JIT)
        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). */
@@ -116,7 +109,7 @@ void stacktrace_stackframeinfo_add(stackframeinfo_t *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
                        {
@@ -135,7 +128,7 @@ void stacktrace_stackframeinfo_add(stackframeinfo_t *sfi, u1 *pv, u1 *sp, u1 *ra
        code = code_get_codeinfo_for_pv(pv);
 
        /* XXX */
-/*     assert(m != NULL); */
+       /*      assert(m != NULL); */
 
 #if defined(ENABLE_JIT)
 # if defined(ENABLE_INTRP)
@@ -154,14 +147,13 @@ void stacktrace_stackframeinfo_add(stackframeinfo_t *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);
@@ -183,7 +175,7 @@ void stacktrace_stackframeinfo_add(stackframeinfo_t *sfi, u1 *pv, u1 *sp, u1 *ra
 
        /* Fill new stackframeinfo structure. */
 
-       sfi->prev = *psfi;
+       sfi->prev = currentsfi;
        sfi->code = code;
        sfi->pv   = pv;
        sfi->sp   = sp;
@@ -203,7 +195,7 @@ void stacktrace_stackframeinfo_add(stackframeinfo_t *sfi, u1 *pv, u1 *sp, u1 *ra
 
        /* 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
@@ -222,17 +214,11 @@ void stacktrace_stackframeinfo_add(stackframeinfo_t *sfi, u1 *pv, u1 *sp, u1 *ra
 
 void stacktrace_stackframeinfo_remove(stackframeinfo_t *sfi)
 {
-       stackframeinfo_t **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;
-
 #if !defined(NDEBUG)
        if (opt_DebugStackFrameInfo) {
                log_start();
@@ -244,9 +230,9 @@ void stacktrace_stackframeinfo_remove(stackframeinfo_t *sfi)
        }
 #endif
 
-       /* restore the old pointer */
+       /* Set previous stackframe info. */
 
-       *psfi = sfi->prev;
+       threads_set_current_stackframeinfo(sfi->prev);
 }
 
 
@@ -282,18 +268,8 @@ static inline void stacktrace_stackframeinfo_fill(stackframeinfo_t *tmpsfi, stac
        tmpsfi->prev = sfi->prev;
 
 #if !defined(NDEBUG)
-       /* Print current method information. */
-
-       if (opt_DebugStackTrace) {
-               log_println("[stacktrace start]");
-               log_start();
-               log_print("[stacktrace: method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
-                                 tmpsfi->code->m, tmpsfi->pv, tmpsfi->sp, tmpsfi->ra,
-                                 tmpsfi->xpc);
-               method_print(tmpsfi->code->m);
-               log_print("]");
-               log_finish();
-       }
+       if (opt_DebugStackTrace)
+               log_println("[stacktrace fill]");
 #endif
 }
 
@@ -360,7 +336,7 @@ static inline void stacktrace_stackframeinfo_next(stackframeinfo_t *tmpsfi)
 
 #if defined(ENABLE_INTRP)
        if (opt_intrp)
-               pv = codegen_get_pv_from_pc(ra);
+               pv = methodtree_find(ra);
        else
 #endif
                {
@@ -532,18 +508,20 @@ static int stacktrace_depth(stackframeinfo_t *sfi)
 
 /* stacktrace_get **************************************************************
 
-   Builds and returns a stacktrace from the current thread for and
-   returns the stacktrace structure wrapped in a Java byte-array to
-   not confuse the GC.
+   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.
+
+   IN:
+       sfi ... stackframe info to start stacktrace from
 
    RETURN:
        stacktrace as Java byte-array
 
 *******************************************************************************/
 
-java_handle_bytearray_t *stacktrace_get(void)
+java_handle_bytearray_t *stacktrace_get(stackframeinfo_t *sfi)
 {
-       stackframeinfo_t        *sfi;
        stackframeinfo_t         tmpsfi;
        int                      depth;
        java_handle_bytearray_t *ba;
@@ -564,10 +542,6 @@ java_handle_bytearray_t *stacktrace_get(void)
        skip_fillInStackTrace = true;
        skip_init             = true;
 
-       /* Get the stacktrace depth of the current thread. */
-
-       sfi = STACKFRAMEINFO;
-
        depth = stacktrace_depth(sfi);
 
        if (depth == 0)
@@ -623,7 +597,7 @@ java_handle_bytearray_t *stacktrace_get(void)
                        /* For GNU Classpath we also need to skip
                           VMThrowable.fillInStackTrace(). */
 
-                       if ((m->class == class_java_lang_VMThrowable) &&
+                       if ((m->clazz == class_java_lang_VMThrowable) &&
                                (m->name  == utf_fillInStackTrace))
                                continue;
 #endif
@@ -639,8 +613,8 @@ java_handle_bytearray_t *stacktrace_get(void)
                   exception we are going to skipping them in stack trace. */
 
                if (skip_init == true) {
-                       if (m->name == utf_init) {
-/*                             throwable->is_a(method->method_holder())) { */
+                       if ((m->name == utf_init) &&
+                               (class_issubclass(m->clazz, class_java_lang_Throwable))) {
                                continue;
                        }
                        else {
@@ -683,6 +657,105 @@ 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.
@@ -693,12 +766,12 @@ return_NULL:
 
 *******************************************************************************/
 
-classloader *stacktrace_first_nonnull_classloader(void)
+classloader_t *stacktrace_first_nonnull_classloader(void)
 {
        stackframeinfo_t *sfi;
        stackframeinfo_t  tmpsfi;
        methodinfo       *m;
-       classloader      *cl;
+       classloader_t    *cl;
 
 #if !defined(NDEBUG)
        if (opt_DebugStackTrace)
@@ -707,7 +780,7 @@ classloader *stacktrace_first_nonnull_classloader(void)
 
        /* Get the stackframeinfo of the current thread. */
 
-       sfi = STACKFRAMEINFO;
+       sfi = threads_get_current_stackframeinfo();
 
        /* Iterate over the whole stack. */
 
@@ -716,7 +789,7 @@ classloader *stacktrace_first_nonnull_classloader(void)
                 stacktrace_stackframeinfo_next(&tmpsfi)) {
 
                m  = tmpsfi.code->m;
-               cl = class_get_classloader(m->class);
+               cl = class_get_classloader(m->clazz);
 
                if (cl != NULL)
                        return cl;
@@ -753,7 +826,7 @@ java_handle_objectarray_t *stacktrace_getClassContext(void)
                log_println("[stacktrace_getClassContext]");
 #endif
 
-       sfi = STACKFRAMEINFO;
+       sfi = threads_get_current_stackframeinfo();
 
        /* Get the depth of the current stack. */
 
@@ -801,7 +874,7 @@ java_handle_objectarray_t *stacktrace_getClassContext(void)
 
                /* Store the class in the array. */
 
-               data[i] = (java_object_t *) m->class;
+               data[i] = (java_object_t *) m->clazz;
 
                i++;
        }
@@ -847,7 +920,7 @@ classinfo *stacktrace_get_current_class(void)
 
        /* Get the stackframeinfo of the current thread. */
 
-       sfi = STACKFRAMEINFO;
+       sfi = threads_get_current_stackframeinfo();
 
        /* If the stackframeinfo is NULL then FindClass is called through
           the Invocation Interface and we return NULL */
@@ -867,16 +940,16 @@ classinfo *stacktrace_get_current_class(void)
 
                m = tmpsfi.code->m;
 
-               if (m->class == class_java_security_PrivilegedAction) {
+               if (m->clazz == class_java_security_PrivilegedAction) {
                        CYCLES_STATS_END(stacktrace_getCurrentClass);
 
                        return NULL;
                }
 
-               if (m->class != NULL) {
+               if (m->clazz != NULL) {
                        CYCLES_STATS_END(stacktrace_getCurrentClass);
 
-                       return m->class;
+                       return m->clazz;
                }
        }
 
@@ -921,7 +994,7 @@ java_handle_objectarray_t *stacktrace_get_stack(void)
 
        /* Get the stackframeinfo of the current thread. */
 
-       sfi = STACKFRAMEINFO;
+       sfi = threads_get_current_stackframeinfo();
 
        /* Get the depth of the current stack. */
 
@@ -974,7 +1047,7 @@ java_handle_objectarray_t *stacktrace_get_stack(void)
                /* NOTE: We use a LLNI-macro here, because a classinfo is not
                   a handle. */
 
-               LLNI_array_direct(classes, i) = (java_object_t *) m->class;
+               LLNI_array_direct(classes, i) = (java_object_t *) m->clazz;
 
                /* Store the name in the array. */
 
@@ -1000,6 +1073,51 @@ return_NULL:
 #endif
 
 
+/* stacktrace_print_entry ****************************************************
+
+   Print line for a stacktrace entry.
+
+   ARGUMENTS:
+       m ............ methodinfo of the entry
+       linenumber ... linenumber of the entry
+
+*******************************************************************************/
+
+static void stacktrace_print_entry(methodinfo *m, int32_t linenumber)
+{
+       /* Sanity check. */
+
+       assert(m != NULL);
+
+       printf("\tat ");
+
+       if (m->flags & ACC_METHOD_BUILTIN)
+               printf("NULL");
+       else
+               utf_display_printable_ascii_classname(m->clazz->name);
+
+       printf(".");
+       utf_display_printable_ascii(m->name);
+       utf_display_printable_ascii(m->descriptor);
+
+       if (m->flags & ACC_NATIVE) {
+               puts("(Native Method)");
+       }
+       else {
+               if (m->flags & ACC_METHOD_BUILTIN) {
+                       puts("(builtin)");
+               }
+               else {
+                       printf("(");
+                       utf_display_printable_ascii(m->clazz->sourcefile);
+                       printf(":%d)\n", linenumber);
+               }
+       }
+
+       fflush(stdout);
+}
+
+
 /* stacktrace_print ************************************************************
 
    Print the given stacktrace with CACAO intern methods only (no Java
@@ -1029,28 +1147,99 @@ void stacktrace_print(stacktrace_t *st)
 
                linenumber = linenumbertable_linenumber_for_pc(&m, ste->code, ste->pc);
 
-               printf("\tat ");
-               utf_display_printable_ascii_classname(m->class->name);
-               printf(".");
-               utf_display_printable_ascii(m->name);
-               utf_display_printable_ascii(m->descriptor);
+               stacktrace_print_entry(m, linenumber);
+       }
+}
 
-               if (m->flags & ACC_NATIVE) {
-                       puts("(Native Method)");
-               }
-               else {
-                       printf("(");
-                       utf_display_printable_ascii(m->class->sourcefile);
-                       printf(":%d)\n", 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;
        }
 
-       /* just to be sure */
+       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;
 
-       fflush(stdout);
+               /* 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
@@ -1064,9 +1253,12 @@ void stacktrace_print(stacktrace_t *st)
 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;
        stacktrace_t            *st;
 
@@ -1080,16 +1272,18 @@ void stacktrace_print_exception(java_handle_t *h)
 #if defined(WITH_CLASSPATH_GNU)
 
        LLNI_field_get_ref(o,   vmState, vmt);
-       LLNI_field_get_ref(vmt, vmData,  ba);
+       LLNI_field_get_ref(vmt, vmdata,  backtrace);
 
 #elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
 
-       LLNI_field_get_ref(o, backtrace, ba);
+       LLNI_field_get_ref(o, backtrace, backtrace);
 
 #else
 # error unknown classpath configuration
 #endif
 
+       ba = (java_handle_bytearray_t *) backtrace;
+
        /* Sanity check. */
 
        assert(ba != NULL);