/* 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)
CYCLES_STATS_DECLARE(stacktrace_get, 40, 5000)
CYCLES_STATS_DECLARE(stacktrace_getClassContext , 40, 5000)
CYCLES_STATS_DECLARE(stacktrace_getCurrentClass , 40, 5000)
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). */
if (pv == NULL) {
#if defined(ENABLE_INTRP)
if (opt_intrp)
- pv = codegen_get_pv_from_pc(ra);
+ pv = methodtree_find(ra);
else
#endif
{
code = code_get_codeinfo_for_pv(pv);
/* XXX */
-/* assert(m != NULL); */
+ /* assert(m != NULL); */
#if defined(ENABLE_JIT)
# if defined(ENABLE_INTRP)
ra = md_stacktrace_get_returnaddress(sp, framesize);
# else
- /* If the method is a non-leaf function, we need to get the return
- address from the stack. For leaf functions the return address
- is set correctly. This makes the assembler and the signal
- handler code simpler. */
-
- isleafmethod = *((s4 *) (pv + IsLeaf));
+ /* If the method is a non-leaf function, we need to get the
+ return address from the stack. For leaf functions the
+ return address is set correctly. This makes the assembler
+ and the signal handler code simpler. The code is NULL is
+ the asm_vm_call_method special case. */
- if (!isleafmethod) {
+ if ((code == NULL) || !code_is_leafmethod(code)) {
framesize = *((u4 *) (pv + FrameSize));
ra = md_stacktrace_get_returnaddress(sp, framesize);
/* Fill new stackframeinfo structure. */
- sfi->prev = *psfi;
+ sfi->prev = currentsfi;
sfi->code = code;
sfi->pv = pv;
sfi->sp = sp;
/* 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
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();
}
#endif
- /* restore the old pointer */
+ /* Set previous stackframe info. */
- *psfi = sfi->prev;
+ threads_set_current_stackframeinfo(sfi->prev);
}
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
}
#if defined(ENABLE_INTRP)
if (opt_intrp)
- pv = codegen_get_pv_from_pc(ra);
+ pv = methodtree_find(ra);
else
#endif
{
/* 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;
skip_fillInStackTrace = true;
skip_init = true;
- /* Get the stacktrace depth of the current thread. */
-
- sfi = STACKFRAMEINFO;
-
depth = stacktrace_depth(sfi);
if (depth == 0)
/* 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
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 {
}
+/* 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.
*******************************************************************************/
-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)
/* Get the stackframeinfo of the current thread. */
- sfi = STACKFRAMEINFO;
+ sfi = threads_get_current_stackframeinfo();
/* Iterate over the whole stack. */
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;
log_println("[stacktrace_getClassContext]");
#endif
- sfi = STACKFRAMEINFO;
+ sfi = threads_get_current_stackframeinfo();
/* Get the depth of the current stack. */
/* Store the class in the array. */
- data[i] = (java_object_t *) m->class;
+ data[i] = (java_object_t *) m->clazz;
i++;
}
/* 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 */
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;
}
}
/* Get the stackframeinfo of the current thread. */
- sfi = STACKFRAMEINFO;
+ sfi = threads_get_current_stackframeinfo();
/* Get the depth of the current stack. */
/* 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. */
#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
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
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;
#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);