-/* 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,
C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
Contact: cacao@cacaojvm.org
Authors: Joseph Wenninger
-
- Changes: Christian Thalinger
+ Christian Thalinger
Edwin Steiner
- $Id: stacktrace.c 4921 2006-05-15 14:24:36Z twisti $
+ $Id: stacktrace.c 6251 2006-12-27 23:15:56Z twisti $
*/
#include "vm/types.h"
-#include "mm/boehm.h"
+#include "mm/gc-common.h"
#include "mm/memory.h"
#include "native/native.h"
#include "vm/global.h" /* required here for native includes */
-#include "native/include/java_lang_ClassLoader.h"
#include "native/include/java_lang_Throwable.h"
-#include "native/include/java_lang_VMThrowable.h"
+
+#if defined(WITH_CLASSPATH_GNU)
+# include "native/include/java_lang_VMThrowable.h"
+#endif
#if defined(ENABLE_THREADS)
# include "threads/native/threads.h"
#include "vm/cycles-stats.h"
-/* linenumbertable_entry ******************************************************/
-
-/* 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(ENABLE_THREADS)
{
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 */
- m = *((methodinfo **) (pv + MethodPointer));
+ 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 */
/* if we don't have pv handy */
if (pv == NULL)
- pv = codegen_findmethod(ra);
+ pv = codegen_get_pv_from_pc(ra);
}
#endif
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
}
}
{
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_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_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));
-
- /* Subtract the size of the line number entry of the structure,
- since the line number table start points to the pc. */
-
- 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();
- }
+ codeinfo *code; /* compiled realization of method */
+ s4 linenumber;
- if (((ptrint)pc >= (ptrint)code->entrypoint)
- &&
- ( (pc - (u1*)code->entrypoint) < code->mcodelength ))
- {
- /* found */
- break;
- }
+ /* find the realization of the method the pc is in */
- 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;
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;
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);
+ 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;
/* walk the stack */
*******************************************************************************/
-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);
-
- if (gcstb->entries == NULL)
- goto return_NULL;
+ gcstc->stb.capacity = stb->capacity;
+ gcstc->stb.used = stb->used;
+ gcstc->stb.entries = gcstc->data;
- 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;
/* 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 */
classes->data[i] = (java_objectheader *) c;
str = javastring_new(ste->method->name);
- if (!str)
+ if (str == NULL)
goto return_NULL;
methodnames->data[i] = (java_objectheader *) str;
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;
*******************************************************************************/
-void stacktrace_dump_trace(void)
+void stacktrace_dump_trace(threadobject *thread)
{
stacktracebuffer *stb;
s4 dumpsize;
/* create a stacktrace for the current thread */
- stb = stacktrace_create(THREADOBJECT);
+ stb = stacktrace_create(thread);
/* print stacktrace */
- if (stb) {
+ if (stb)
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);
}