-/* src/vm/jit/stacktrace.c - machine independet stacktrace system
+/* src/vm/jit/stacktrace.c - machine independent stacktrace system
- Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+ 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
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
- Contact: cacao@cacaojvm.org
-
- Authors: Joseph Wenninger
-
- Changes: Christian Thalinger
- Edwin Steiner
-
- $Id: stacktrace.c 4850 2006-04-26 15:44:07Z edwin $
+ $Id: stacktrace.c 7584 2007-03-27 18:17:27Z tbfg $
*/
#include "vm/types.h"
-#include "mm/boehm.h"
+#include "mm/gc-common.h"
#include "mm/memory.h"
-#include "native/native.h"
+
+#include "vm/jit/stacktrace.h"
#include "vm/global.h" /* required here for native includes */
-#include "native/include/java_lang_ClassLoader.h"
+#include "native/jni.h"
#include "native/include/java_lang_Throwable.h"
-#include "native/include/java_lang_VMThrowable.h"
-#if defined(USE_THREADS)
-# if defined(NATIVE_THREADS)
-# include "threads/native/threads.h"
-# else
-# include "threads/green/threads.h"
-# endif
+#if defined(WITH_CLASSPATH_GNU)
+# 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 "toolbox/logging.h"
+
#include "vm/builtin.h"
-#include "vm/class.h"
+#include "vm/cycles-stats.h"
#include "vm/exceptions.h"
-#include "vm/loader.h"
-#include "vm/options.h"
#include "vm/stringlocal.h"
#include "vm/vm.h"
+
#include "vm/jit/asmpart.h"
#include "vm/jit/codegen-common.h"
#include "vm/jit/methodheader.h"
-#include "vm/cycles-stats.h"
-
-/* linenumbertable_entry ******************************************************/
+#include "vmcore/class.h"
+#include "vmcore/loader.h"
+#include "vmcore/options.h"
-/* Keep the type of line the same as the pointer type, otherwise we
- run into alignment troubles (like on MIPS64). */
-
-typedef struct linenumbertable_entry linenumbertable_entry;
-
-struct linenumbertable_entry {
- ptrint line; /* NOTE: see doc/inlining_stacktrace.txt for */
- u1 *pc; /* special meanings of line and pc. */
-};
/* global variables ***********************************************************/
-
-#if !defined(USE_THREADS)
+#if !defined(ENABLE_THREADS)
stackframeinfo *_no_threads_stackframeinfo = NULL;
#endif
{
stackframeinfo **psfi;
methodinfo *m;
+ codeinfo *code;
/* get current stackframe info pointer */
if (pv == NULL) {
#if defined(ENABLE_INTRP)
if (opt_intrp)
- pv = codegen_findmethod(ra);
+ pv = codegen_get_pv_from_pc(ra);
else
#endif
{
#if defined(ENABLE_JIT)
- pv = md_codegen_findmethod(ra);
+ pv = md_codegen_get_pv_from_pc(ra);
#endif
}
}
- /* get methodinfo pointer from data segment */
+ /* get codeinfo pointer from data segment */
+
+ code = *((codeinfo **) (pv + CodeinfoPointer));
- m = *((methodinfo **) (pv + MethodPointer));
+ /* For asm_vm_call_method the codeinfo pointer is NULL. */
+
+ m = (code == NULL) ? NULL : code->m;
/* fill new stackframe info structure */
/* if we don't have pv handy */
if (pv == NULL)
- pv = codegen_findmethod(ra);
+ pv = codegen_get_pv_from_pc(ra);
}
#endif
u1 *sp, u1 *ra, u1 *xpc)
{
stackframeinfo **psfi;
-#if !defined(__I386__) && !defined(__X86_64__)
+#if !defined(__I386__) && !defined(__X86_64__) && !defined(__S390__)
bool isleafmethod;
#endif
#if defined(ENABLE_JIT)
if (pv == NULL) {
#if defined(ENABLE_INTRP)
if (opt_intrp)
- pv = codegen_findmethod(ra);
+ pv = codegen_get_pv_from_pc(ra);
else
#endif
{
#if defined(ENABLE_JIT)
- pv = md_codegen_findmethod(ra);
+# if defined(__SPARC_64__)
+ pv = md_get_pv_from_stackframe(sp);
+# else
+ pv = md_codegen_get_pv_from_pc(ra);
+# endif
#endif
}
}
if (!opt_intrp) {
# endif
-# if defined(__I386__) || defined(__X86_64__)
+# if defined(__I386__) || defined(__X86_64__) || defined(__S390__)
/* On i386 and x86_64 we always have to get the return address
from the stack. */
+ /* On S390 we use REG_RA as REG_ITMP3, so we have always to get
+ the RA from stack. */
framesize = *((u4 *) (pv + FrameSize));
{
stackframeinfo **psfi;
methodinfo *m;
+ codeinfo *code;
- /* get methodinfo pointer from data segment */
+ /* get codeinfo pointer from data segment */
- m = *((methodinfo **) (pv + MethodPointer));
+ code = *((codeinfo **) (pv + CodeinfoPointer));
+
+ /* For asm_vm_call_method the codeinfo pointer is NULL. */
+
+ m = (code == NULL) ? NULL : code->m;
/* get current stackframe info pointer */
/* stacktrace_remove_stackframeinfo ********************************************
- XXX
+ Remove the topmost stackframeinfo in the current thread.
*******************************************************************************/
/* create exception */
- o = new_arithmeticexception();
+ o = exceptions_new_arithmeticexception();
/* remove stackframeinfo */
/* create exception */
- o = new_arrayindexoutofboundsexception(index);
+ o = exceptions_new_arrayindexoutofboundsexception(index);
/* remove stackframeinfo */
/* create exception */
- o = new_arraystoreexception();
+ o = exceptions_new_arraystoreexception();
/* remove stackframeinfo */
*******************************************************************************/
java_objectheader *stacktrace_inline_classcastexception(u1 *pv, u1 *sp, u1 *ra,
- u1 *xpc)
+ u1 *xpc,
+ java_objectheader *o)
{
stackframeinfo sfi;
- java_objectheader *o;
+ java_objectheader *e;
/* create stackframeinfo */
/* create exception */
- o = new_classcastexception();
+ e = exceptions_new_classcastexception(o);
/* remove stackframeinfo */
stacktrace_remove_stackframeinfo(&sfi);
- return o;
+ return e;
}
/* create exception */
- o = new_nullpointerexception();
+ o = exceptions_new_nullpointerexception();
/* remove stackframeinfo */
/* resolve methodinfo pointer from exception object */
+#if defined(ENABLE_JAVASE)
m = class_resolvemethod(o->vftbl->class,
utf_fillInStackTrace,
utf_void__java_lang_Throwable);
+#elif defined(ENABLE_JAVAME_CLDC1_1)
+ m = class_resolvemethod(o->vftbl->class,
+ utf_fillInStackTrace,
+ utf_void__void);
+#else
+#error IMPLEMENT ME!
+#endif
/* call function */
/* create exception */
- o = new_arithmeticexception();
+ o = exceptions_new_arithmeticexception();
/* remove stackframeinfo */
/* create exception */
- o = new_nullpointerexception();
+ o = exceptions_new_nullpointerexception();
/* remove stackframeinfo */
}
-/* stacktrace_add_method_intern ************************************************
-
- This function is used by stacktrace_add_method to search the line number
- table for the line corresponding to a given pc. The function recurses for
- inlined methods.
-
-*******************************************************************************/
-
-static bool stacktrace_add_method_intern(stacktracebuffer *stb,
- methodinfo *m,
- linenumbertable_entry *lntentry,
- ptrint lntsize,
- u1 *pc)
-{
- linenumbertable_entry *lntinline; /* special entry for inlined method */
-
- assert(stb);
- assert(lntentry);
-
- /* Find the line number for the specified PC (going backwards
- in the linenumber table). The linenumber table size is zero
- in native stubs. */
-
- for (; lntsize > 0; lntsize--, lntentry--) {
-
- /* did we reach the current line? */
-
- /* Note: In case of inlining this may actually compare the pc
- against a methodinfo *, yielding a non-sensical
- result. This is no problem, however, as we ignore such
- entries in the switch below. This way we optimize for the
- common case (ie. a real pc in lntentry->pc). */
-
- if (pc >= lntentry->pc) {
-
- /* check for special inline entries (see
- doc/inlining_stacktrace.txt for details */
-
- if ((s4)lntentry->line < 0) {
- switch (lntentry->line) {
- case -1:
- /* begin of inlined method (ie. INLINE_END
- instruction) */
-
- lntinline = --lntentry;/* get entry with methodinfo * */
- lntentry--; /* skip the special entry */
- lntsize -= 2;
-
- /* search inside the inlined method */
- if (stacktrace_add_method_intern(
- stb,
- (methodinfo*) lntinline->pc,
- lntentry,
- lntsize,
- pc))
- {
- /* the inlined method contained the pc */
- assert(lntinline->line <= -3);
- stacktrace_add_entry(stb, m, (-3) - lntinline->line);
- return true;
- }
- /* pc was not in inlined method, continue
- search. Entries inside the inlined method
- will be skipped because their lntentry->pc
- is higher than pc. */
- break;
-
- case -2:
- /* end of inlined method */
- return false;
-
- /* default: is only reached for an -3-line entry
- after a skipped -2 entry. We can safely ignore
- it and continue searching. */
- }
- }
- else {
- /* found a normal entry */
- stacktrace_add_entry(stb, m, lntentry->line);
- return true;
- }
- }
- }
-
- /* not found */
- return false;
-}
-
/* stacktrace_add_method *******************************************************
Add stacktrace entries[1] for the given method to the stacktrace buffer.
static bool stacktrace_add_method(stacktracebuffer *stb, methodinfo *m, u1 *pv,
u1 *pc)
{
- ptrint lntsize; /* size of line number table */
- u1 *lntstart; /* start of line number table */
- linenumbertable_entry *lntentry; /* points to last entry in the table */
- codeinfo *code; /* compiled realization of method */
-
- /* get size of line number table */
-
- lntsize = *((ptrint *) (pv + LineNumberTableSize));
- lntstart = *((u1 **) (pv + LineNumberTableStart));
+ codeinfo *code; /* compiled realization of method */
+ s4 linenumber;
- /* Subtract the size of the line number entry of the structure,
- since the line number table start points to the pc. */
+ /* find the realization of the method the pc is in */
- lntentry = (linenumbertable_entry *) (lntstart - SIZEOF_VOID_P);
-
- /* find the realization of the method the pc is in */
- /* XXX Note: This is preliminary. It would be cleaner */
- /* to get the codeinfo * from the PV */
-
- code = m->code;
- while (1) {
- if (!code) {
-#ifndef NDEBUG
- method_println(m);
- dolog("Could not find codeinfo for Current PC: %p",(void*)pc);
-#endif
- abort();
- }
-
- if (((ptrint)pc >= (ptrint)code->entrypoint)
- &&
- ( (pc - (u1*)code->entrypoint) < code->mcodelength ))
- {
- /* found */
- break;
- }
-
- code = code->prev;
- }
+ code = *((codeinfo **) (pv + CodeinfoPointer));
/* search the line number table */
- if (stacktrace_add_method_intern(stb, m, lntentry, lntsize, pc))
- return true;
+ linenumber = dseg_get_linenumber_from_pc(&m, pv, pc);
- /* If we get here, just add the entry with line number 0. */
+ /* now add a new entry to the staktrace */
- stacktrace_add_entry(stb, m, 0);
+ stacktrace_add_entry(stb, m, linenumber);
return true;
}
stacktracebuffer *stb;
stackframeinfo *sfi;
methodinfo *m;
+ codeinfo *code;
u1 *pv;
u1 *sp;
u4 framesize;
native stackframeinfo (VMThrowable.fillInStackTrace is a native
function). */
-#if defined(USE_THREADS)
- sfi = thread->info._stackframeinfo;
+ /* We don't use the STACKFRAMEINFO macro here, as we have to use
+ the passed thread. */
+
+#if defined(ENABLE_THREADS)
+ sfi = thread->_stackframeinfo;
#else
sfi = _no_threads_stackframeinfo;
#endif
m = NULL;
- while (m || sfi) {
+ 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. */
#if defined(ENABLE_INTRP)
if (opt_intrp)
- pv = codegen_findmethod(ra);
+ pv = codegen_get_pv_from_pc(ra);
else
#endif
{
#if defined(ENABLE_JIT)
- pv = md_codegen_findmethod(ra);
+ pv = md_codegen_get_pv_from_pc(ra);
#endif
}
/* get methodinfo pointer from parent data segment */
- m = *((methodinfo **) (pv + MethodPointer));
+ code = *((codeinfo **) (pv + CodeinfoPointer));
+
+ /* For asm_vm_call_method the codeinfo pointer is
+ NULL. */
+
+ m = (code == NULL) ? NULL : code->m;
} else {
/* Inline stackframe infos are special: they have a
/* get methodinfo from current Java method */
- m = *((methodinfo **) (pv + MethodPointer));
+ code = *((codeinfo **) (pv + CodeinfoPointer));
+
+ /* For asm_vm_call_method the codeinfo pointer is
+ NULL. */
+
+ m = (code == NULL) ? NULL : code->m;
/* if m == NULL, this is a asm_calljavafunction call */
fflush(stdout);
#endif
- /* set stack pointer to stackframe of parent Java */
- /* function of the current Java function */
+ /* Set stack pointer to stackframe of parent Java
+ function of the current Java function. */
#if defined(__I386__) || defined (__X86_64__)
sp += framesize + SIZEOF_VOID_P;
+#elif defined(__SPARC_64__)
+ sp = md_get_framepointer(sp);
#else
sp += framesize;
#endif
- /* get data segment and methodinfo pointer from parent */
- /* method */
+ /* get data segment and methodinfo pointer from
+ parent method */
#if defined(ENABLE_JIT)
- pv = md_codegen_findmethod(ra);
+ pv = md_codegen_get_pv_from_pc(ra);
#endif
- m = *((methodinfo **) (pv + MethodPointer));
+ code = *((codeinfo **) (pv + CodeinfoPointer));
+
+ /* For asm_vm_call_method the codeinfo pointer is
+ NULL. */
+
+ m = (code == NULL) ? NULL : code->m;
#if defined(ENABLE_INTRP)
}
#if defined(ENABLE_INTRP)
if (opt_intrp)
- pv = codegen_findmethod(ra);
+ pv = codegen_get_pv_from_pc(ra);
else
#endif
{
#if defined(ENABLE_JIT)
- pv = md_codegen_findmethod(ra);
+# 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
}
- m = *((methodinfo **) (pv + MethodPointer));
+ code = *((codeinfo **) (pv + CodeinfoPointer));
+
+ /* For asm_vm_call_method the codeinfo pointer is NULL. */
+
+ m = (code == NULL) ? NULL : code->m;
/* walk the stack */
else
#endif
{
-#if defined(__I386__) || defined (__X86_64__)
+#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
*******************************************************************************/
-stacktracebuffer *stacktrace_fillInStackTrace(void)
+stacktracecontainer *stacktrace_fillInStackTrace(void)
{
- stacktracebuffer *stb;
- stacktracebuffer *gcstb;
- s4 dumpsize;
+ stacktracebuffer *stb;
+ stacktracecontainer *gcstc;
+ s4 gcstc_size;
+ s4 dumpsize;
CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
/* mark start of dump memory area */
goto return_NULL;
/* allocate memory from the GC heap and copy the stacktrace buffer */
+ /* ATTENTION: use stacktracecontainer for this and make it look like
+ an array */
- gcstb = GCNEW(stacktracebuffer);
+ gcstc_size = sizeof(stacktracebuffer) +
+ sizeof(stacktrace_entry) * stb->used;
+ gcstc = (stacktracecontainer *) builtin_newarray_byte(gcstc_size);
- if (gcstb == NULL)
+ if (gcstc == NULL)
goto return_NULL;
- gcstb->capacity = stb->capacity;
- gcstb->used = stb->used;
- gcstb->entries = GCMNEW(stacktrace_entry, stb->used);
+ gcstc->stb.capacity = stb->capacity;
+ gcstc->stb.used = stb->used;
+ gcstc->stb.entries = gcstc->data;
- if (gcstb->entries == NULL)
- goto return_NULL;
-
- MCOPY(gcstb->entries, stb->entries, stacktrace_entry, stb->used);
+ MCOPY(gcstc->data, stb->entries, stacktrace_entry, stb->used);
/* release dump memory */
CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
stacktrace_overhead)
- return gcstb;
+ return gcstc;
return_NULL:
dump_release(dumpsize);
*******************************************************************************/
+#if defined(ENABLE_JAVASE)
classinfo *stacktrace_getCurrentClass(void)
{
stacktracebuffer *stb;
return NULL;
}
+#endif /* ENABLE_JAVASE */
/* stacktrace_getStack *********************************************************
*******************************************************************************/
+#if defined(ENABLE_JAVASE)
java_objectarray *stacktrace_getStack(void)
{
- stacktracebuffer *stb;
- stacktrace_entry *ste;
- java_objectarray *oa;
- java_objectarray *classes;
- java_objectarray *methodnames;
- classinfo *c;
- java_lang_String *str;
- s4 i;
- s4 dumpsize;
+ stacktracebuffer *stb;
+ stacktrace_entry *ste;
+ java_objectarray *oa;
+ java_objectarray *classes;
+ java_objectarray *methodnames;
+ classinfo *c;
+ java_objectheader *string;
+ s4 i;
+ s4 dumpsize;
CYCLES_STATS_DECLARE_AND_START
/* mark start of dump memory area */
/* create a stacktrace for the current thread */
stb = stacktrace_create(THREADOBJECT);
- if (!stb)
+
+ if (stb == NULL)
goto return_NULL;
/* get the first stacktrace entry */
oa = builtin_anewarray(2, arrayclass_java_lang_Object);
- if (!oa)
+ if (oa == NULL)
goto return_NULL;
classes = builtin_anewarray(stb->used, class_java_lang_Class);
- if (!classes)
+ if (classes == NULL)
goto return_NULL;
methodnames = builtin_anewarray(stb->used, class_java_lang_String);
- if (!methodnames)
+ if (methodnames == NULL)
goto return_NULL;
/* set up the 2-dimensional array */
c = ste->method->class;
classes->data[i] = (java_objectheader *) c;
- str = javastring_new(ste->method->name);
- if (!str)
+ string = javastring_new(ste->method->name);
+
+ if (string == NULL)
goto return_NULL;
- methodnames->data[i] = (java_objectheader *) str;
+ methodnames->data[i] = string;
}
/* return the 2-dimensional array */
return NULL;
}
+#endif /* ENABLE_JAVASE */
/* stacktrace_print_trace_from_buffer ******************************************
*******************************************************************************/
-static void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
+void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
{
stacktrace_entry *ste;
methodinfo *m;
m = ste->method;
printf("\tat ");
- utf_display_classname(m->class->name);
+ utf_display_printable_ascii_classname(m->class->name);
printf(".");
- utf_display(m->name);
- utf_display(m->descriptor);
+ utf_display_printable_ascii(m->name);
+ utf_display_printable_ascii(m->descriptor);
if (m->flags & ACC_NATIVE) {
puts("(Native Method)");
} else {
printf("(");
- utf_display(m->class->sourcefile);
+ utf_display_printable_ascii(m->class->sourcefile);
printf(":%d)\n", (u4) ste->linenumber);
}
}
*******************************************************************************/
-void stacktrace_dump_trace(void)
+void stacktrace_dump_trace(threadobject *thread)
{
stacktracebuffer *stb;
s4 dumpsize;
-#if 0
- /* get methodinfo pointer from data segment */
-
- m = *((methodinfo **) (pv + MethodPointer));
-
- /* get current stackframe info pointer */
-
- psfi = STACKFRAMEINFO;
-
- /* fill new stackframe info structure */
-
- sfi->prev = *psfi;
- sfi->method = NULL;
- sfi->pv = NULL;
- sfi->sp = sp;
- sfi->ra = ra;
-
- /* store new stackframe info pointer */
-
- *psfi = sfi;
-#endif
-
/* mark start of dump memory area */
dumpsize = dump_size();
/* create a stacktrace for the current thread */
- stb = stacktrace_create(THREADOBJECT);
+ stb = stacktrace_create(thread);
/* print stacktrace */
- if (stb) {
+ if (stb != NULL)
stacktrace_print_trace_from_buffer(stb);
-
- } else {
+ else {
puts("\t<<No stacktrace available>>");
fflush(stdout);
}
void stacktrace_print_trace(java_objectheader *xptr)
{
java_lang_Throwable *t;
+#if defined(WITH_CLASSPATH_GNU)
java_lang_VMThrowable *vmt;
+#endif
+ stacktracecontainer *stc;
stacktracebuffer *stb;
t = (java_lang_Throwable *) xptr;
/* now print the stacktrace */
+#if defined(WITH_CLASSPATH_GNU)
vmt = t->vmState;
- stb = (stacktracebuffer *) vmt->vmData;
+ stc = (stacktracecontainer *) vmt->vmData;
+ stb = &(stc->stb);
+#elif defined(WITH_CLASSPATH_CLDC1_1)
+ stc = (stacktracecontainer *) t->backtrace;
+ stb = &(stc->stb);
+#endif
stacktrace_print_trace_from_buffer(stb);
}