-/* src/vm/jit/stacktrace.c
+/* src/vm/jit/stacktrace.c - machine independet stacktrace system
Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
Changes: Christian Thalinger
- $Id: stacktrace.c 3048 2005-07-18 15:07:19Z twisti $
+ $Id: stacktrace.c 3540 2005-11-03 20:33:20Z twisti $
*/
#include <string.h>
#include "config.h"
-#include "asmoffsets.h"
#include "mm/boehm.h"
#include "native/native.h"
#include "vm/class.h"
#include "vm/exceptions.h"
#include "vm/loader.h"
+#include "vm/options.h"
#include "vm/stringlocal.h"
#include "vm/tables.h"
#include "vm/jit/asmpart.h"
#include "vm/jit/codegen.inc.h"
-
-
-#undef JWDEBUG
-#undef JWDEBUG2
-#undef JWDEBUG3
+#include "vm/jit/methodheader.h"
/* lineNumberTableEntry *******************************************************/
-/* The special value of -1 means that a inlined function starts, a value of */
-/* -2 means that an inlined function ends */
+/* Keep the type of line the same as the pointer type, otherwise we run into */
+/* alignment troubles (like on MIPS64). */
typedef struct lineNumberTableEntry {
- ptrint line; /* XXX change me to u2 */
+ ptrint line;
u1 *pc;
} lineNumberTableEntry;
} lineNumberTableEntryInlineBegin;
-typedef void(*CacaoStackTraceCollector)(void **,stackTraceBuffer*);
+typedef bool(*CacaoStackTraceCollector)(void **, stackTraceBuffer*);
#define BLOCK_INITIALSIZE 40
#define BLOCK_SIZEINCREMENT 40
+/* global variables ***********************************************************/
+
+#if !defined(USE_THREADS)
+stackframeinfo *_no_threads_stackframeinfo = NULL;
+#endif
+
+
+/* stacktrace_create_stackframeinfo ********************************************
+
+ Creates an stackframe info structure for inline code in the
+ interpreter.
+
+*******************************************************************************/
+
+#if defined(ENABLE_INTRP)
+void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv,
+ u1 *sp, functionptr ra)
+{
+ stackframeinfo **psfi;
+ methodinfo *m;
+
+ /* get current stackframe info pointer */
+
+ psfi = STACKFRAMEINFO;
+
+ /* if we don't have pv handy */
+
+ if (pv == NULL)
+ pv = (u1 *) (ptrint) codegen_findmethod(ra);
+
+ /* get methodinfo pointer from data segment */
+
+ m = *((methodinfo **) (pv + MethodPointer));
+
+ /* 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 fillInStackTrace */
+
+ sfi->xpc = ra;
+
+ /* store new stackframe info pointer */
+
+ *psfi = sfi;
+}
+#endif /* defined(ENABLE_INTRP) */
+
/* stacktrace_create_inline_stackframeinfo *************************************
Creates an stackframe info structure for an inline exception stub.
u1 *sp, functionptr ra,
functionptr xpc)
{
- void **osfi;
+ stackframeinfo **psfi;
/* get current stackframe info pointer */
- osfi = builtin_asm_get_stackframeinfo();
+ psfi = STACKFRAMEINFO;
+
+#if defined(ENABLE_INTRP)
+ if (opt_intrp) {
+ /* if we don't have pv handy */
+
+ if (pv == NULL)
+ pv = (u1 *) (ptrint) codegen_findmethod(ra);
+
+ }
+#endif
/* fill new stackframe info structure */
- sfi->oldThreadspecificHeadValue = *osfi;
- sfi->addressOfThreadspecificHead = osfi;
+ sfi->prev = *psfi;
sfi->method = NULL;
sfi->pv = pv;
sfi->sp = sp;
/* store new stackframe info pointer */
- *osfi = sfi;
+ *psfi = sfi;
}
u1 *sp, functionptr ra,
functionptr xpc)
{
- void **osfi;
+ stackframeinfo **psfi;
#if !defined(__I386__) && !defined(__X86_64__)
- bool isleafmethod;
+ bool isleafmethod;
#endif
- s4 framesize;
+ s4 framesize;
/* get current stackframe info pointer */
- osfi = builtin_asm_get_stackframeinfo();
+ psfi = STACKFRAMEINFO;
- /* sometimes we don't have pv handy (e.g. in asmpart.S: */
- /* L_asm_call_jit_compiler_exception) */
+ /* 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)
pv = (u1 *) (ptrint) codegen_findmethod(ra);
-#if defined(__I386__) || defined(__X86_64__)
- /* On i386 and x86_64 we always have to get the return address from the */
- /* stack. */
-
- framesize = *((u4 *) (pv + FrameSize));
+#if defined(ENABLE_INTRP)
+ /* When using the interpreter, we pass RA to the function. */
- 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 (!opt_intrp) {
+#endif
+# if defined(__I386__) || defined(__X86_64__)
+ /* On i386 and x86_64 we always have to get the return address
+ from the stack. */
- if (!isleafmethod) {
framesize = *((u4 *) (pv + FrameSize));
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 (!isleafmethod) {
+ framesize = *((u4 *) (pv + FrameSize));
+
+ ra = md_stacktrace_get_returnaddress(sp, framesize);
+ }
+# endif
+#if defined(ENABLE_INTRP)
}
#endif
/* fill new stackframe info structure */
- sfi->oldThreadspecificHeadValue = *osfi;
- sfi->addressOfThreadspecificHead = osfi;
+ sfi->prev = *psfi;
sfi->method = NULL;
sfi->pv = pv;
sfi->sp = sp;
/* store new stackframe info pointer */
- *osfi = sfi;
+ *psfi = sfi;
}
void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv,
u1 *sp, functionptr ra)
{
- void **osfi;
- methodinfo *m;
+ stackframeinfo **psfi;
+ methodinfo *m;
/* get methodinfo pointer from data segment */
/* get current stackframe info pointer */
- osfi = builtin_asm_get_stackframeinfo();
+ psfi = STACKFRAMEINFO;
/* fill new stackframe info structure */
- sfi->oldThreadspecificHeadValue = *osfi;
- sfi->addressOfThreadspecificHead = osfi;
+ sfi->prev = *psfi;
sfi->method = m;
sfi->pv = NULL;
sfi->sp = sp;
/* store new stackframe info pointer */
- *osfi = sfi;
+ *psfi = sfi;
}
void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
{
- void **osfi;
+ stackframeinfo **psfi;
- /* get address of pointer */
+ /* get current stackframe info pointer */
- osfi = sfi->addressOfThreadspecificHead;
+ psfi = STACKFRAMEINFO;
/* restore the old pointer */
- *osfi = sfi->oldThreadspecificHeadValue;
+ *psfi = sfi->prev;
}
}
-/* stacktrace_inline_negativearraysizeexception ********************************
-
- Creates an NegativeArraySizeException for inline stub.
-
-*******************************************************************************/
-
-java_objectheader *stacktrace_inline_negativearraysizeexception(u1 *pv, u1 *sp,
- functionptr ra,
- functionptr xpc)
-{
- stackframeinfo sfi;
- java_objectheader *o;
-
- /* create stackframeinfo */
-
- stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
-
- /* create exception */
-
- o = new_negativearraysizeexception();
-
- /* remove stackframeinfo */
-
- stacktrace_remove_stackframeinfo(&sfi);
-
- return o;
-}
-
-
/* stacktrace_inline_nullpointerexception **************************************
Creates an NullPointerException for inline stub.
}
-/* stacktrace_extern_fillInStackTrace ******************************************
-
- Fills in the correct stacktrace into an existing exception object
- (this one is for calling from assembler code).
-
-*******************************************************************************/
-
-java_objectheader *stacktrace_extern_fillInStackTrace(u1 *pv, u1 *sp,
- functionptr ra,
- functionptr xpc)
-{
- java_objectheader *o;
- stackframeinfo sfi;
- methodinfo *m;
-
- /* get exception */
-
- o = *exceptionptr;
-
- /* create stackframeinfo */
-
- stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
-
- /* clear exception */
-
- *exceptionptr = NULL;
-
- /* resolve methodinfo pointer from exception object */
-
- m = class_resolvemethod(o->vftbl->class,
- utf_fillInStackTrace,
- utf_void__java_lang_Throwable);
-
- /* call function */
-
- asm_calljavafunction(m, o, NULL, NULL, NULL);
-
- /* remove stackframeinfo */
-
- stacktrace_remove_stackframeinfo(&sfi);
-
- return o;
-}
-
-
/* addEntry ********************************************************************
XXX
*******************************************************************************/
static bool stacktrace_fillInStackTrace_methodRecursive(stackTraceBuffer *buffer,
- methodinfo *method,
+ methodinfo *m,
lineNumberTableEntry *lntentry,
s4 lntsize,
u1 *pc)
&ent,
&ahead,
pc)) {
- addEntry(buffer, method, ilStart->lineNrOuter);
+ addEntry(buffer, m, ilStart->lineNrOuter);
return true;
}
#endif
default:
- addEntry(buffer, method, lntentry->line);
+ addEntry(buffer, m, lntentry->line);
return true;
}
}
}
- /* this should not happen */
+ /* check if we are before the actual JIT code */
+
+ if ((ptrint) pc < (ptrint) m->entrypoint) {
+ dolog("Current pc before start of code: %p < %p", pc, m->entrypoint);
+ assert(0);
+ }
+
+ /* otherwise just add line 0 */
- assert(0);
+ addEntry(buffer, m, 0);
- return false;
+ return true;
}
methodinfo *method, u1 *pv,
u1 *pc)
{
- s4 lntsize; /* size of line number table */
+ ptrint lntsize; /* size of line number table */
u1 *lntstart; /* start of line number table */
lineNumberTableEntry *lntentry; /* points to last entry in the table */
/* get size of line number table */
- lntsize = *((s4 *) (pv + LineNumberTableSize));
- lntstart = *((u1 **) (pv + LineNumberTableStart));
+ 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 */
- /* XXX change me to u2 (or s4) */
-
lntentry = (lineNumberTableEntry *) (lntstart - SIZEOF_VOID_P);
if (lntsize == 0) {
*******************************************************************************/
-void cacao_stacktrace_fillInStackTrace(void **target,
- CacaoStackTraceCollector coll)
+static bool cacao_stacktrace_fillInStackTrace(void **target,
+ CacaoStackTraceCollector coll)
{
stacktraceelement primaryBlock[BLOCK_INITIALSIZE*sizeof(stacktraceelement)];
stackTraceBuffer buffer;
- stackframeinfo *info;
+ stackframeinfo *sfi;
methodinfo *m;
u1 *pv;
u1 *sp;
u4 framesize;
functionptr ra;
functionptr xpc;
+ bool result;
/* prevent compiler warnings */
/* the first element in the stackframe chain must always be a native */
/* stackframeinfo (VMThrowable.fillInStackTrace is a native function) */
- info = *((void **) builtin_asm_get_stackframeinfo());
+ sfi = *STACKFRAMEINFO;
- if (!info) {
+ if (!sfi) {
*target = NULL;
- return;
+ return true;
}
#define PRINTMETHODS 0
#if PRINTMETHODS
printf("\n\nfillInStackTrace start:\n");
+ fflush(stdout);
#endif
/* loop while we have a method pointer (asm_calljavafunction has NULL) or */
m = NULL;
- while (m || info) {
+ while (m || sfi) {
/* m == NULL should only happen for the first time and inline */
/* stackframe infos, like from the exception stubs or the patcher */
/* wrapper */
if (m == NULL) {
/* for native stub stackframe infos, pv is always NULL */
- if (info->pv == NULL) {
+ if (sfi->pv == NULL) {
/* get methodinfo, sp and ra from the current stackframe info */
- m = info->method;
- sp = info->sp; /* sp of parent Java function */
- ra = info->ra;
+ m = sfi->method;
+ sp = sfi->sp; /* sp of parent Java function */
+ ra = sfi->ra;
if (m)
addEntry(&buffer, m, 0);
utf_display(m->name);
utf_display(m->descriptor);
printf(": native stub\n");
+ fflush(stdout);
#endif
/* this is an native stub stackframe info, so we can get the */
/* parent pv from the return address (ICMD_INVOKE*) */
/* get methodinfo, sp and ra from the current stackframe info */
- m = info->method; /* m == NULL */
- pv = info->pv; /* pv of parent Java function */
- sp = info->sp; /* sp of parent Java function */
- ra = info->ra; /* ra of parent Java function */
- xpc = info->xpc; /* actual exception position */
+ m = sfi->method; /* m == NULL */
+ pv = sfi->pv; /* pv of parent Java function */
+ sp = sfi->sp; /* sp of parent Java function */
+ ra = sfi->ra; /* ra of parent Java function */
+ xpc = sfi->xpc; /* actual exception position */
#if PRINTMETHODS
printf("NULL: inline stub\n");
+ fflush(stdout);
#endif
/* get methodinfo from current Java method */
/* if m == NULL, this is a asm_calljavafunction call */
if (m != NULL) {
+#if PRINTMETHODS
+ utf_display_classname(m->class->name);
+ printf(".");
+ utf_display(m->name);
+ utf_display(m->descriptor);
+ printf(": inline stub parent\n");
+ fflush(stdout);
+#endif
+
+#if defined(ENABLE_INTRP)
+ if (!opt_intrp) {
+#endif
/* add it to the stacktrace */
pv = (u1 *) (ptrint) codegen_findmethod(ra);
m = *((methodinfo **) (pv + MethodPointer));
+
+#if defined(ENABLE_INTRP)
+ }
+#endif
+ }
+#if PRINTMETHODS
+ else {
+ printf("asm_calljavafunction\n");
+ fflush(stdout);
}
+#endif
}
- /* get next stackframeinfo in the chain */
+ /* get previous stackframeinfo in the chain */
- info = info->oldThreadspecificHeadValue;
+ sfi = sfi->prev;
} else {
#if PRINTMETHODS
/* walk the stack */
+#if defined(ENABLE_INTRP)
+ if (opt_intrp)
+ sp = *(u1 **)(sp - framesize);
+ else
+#endif
+ {
#if defined(__I386__) || defined (__X86_64__)
- sp += framesize + SIZEOF_VOID_P;
+ sp += framesize + SIZEOF_VOID_P;
#else
- sp += framesize;
+ sp += framesize;
#endif
+ }
}
}
if (coll)
- coll(target, &buffer);
+ result = coll(target, &buffer);
if (buffer.needsFree)
free(buffer.start);
+
+ return result;
}
-static
-void stackTraceCollector(void **target, stackTraceBuffer *buffer) {
- stackTraceBuffer *dest=*target=heap_allocate(sizeof(stackTraceBuffer)+buffer->full*sizeof(stacktraceelement),true,0);
- memcpy(*target,buffer,sizeof(stackTraceBuffer));
- memcpy(dest+1,buffer->start,buffer->full*sizeof(stacktraceelement));
+/* stackTraceCollector *********************************************************
- dest->needsFree=0;
- dest->size=dest->full;
- dest->start=(stacktraceelement*)(dest+1);
+ XXX
+
+*******************************************************************************/
+
+static bool stackTraceCollector(void **target, stackTraceBuffer *buffer)
+{
+ stackTraceBuffer *dest;
+
+ dest = *target = heap_allocate(sizeof(stackTraceBuffer) + buffer->full * sizeof(stacktraceelement), true, 0);
- /*
- if (buffer->full>0) {
- printf("SOURCE BUFFER:%s\n",buffer->start[0].method->name->text);
- printf("DEST BUFFER:%s\n",dest->start[0].method->name->text);
- } else printf("Buffer is empty\n");
- */
+ if (!dest)
+ return false;
+
+ memcpy(*target, buffer, sizeof(stackTraceBuffer));
+ memcpy(dest + 1, buffer->start, buffer->full * sizeof(stacktraceelement));
+
+ dest->needsFree = 0;
+ dest->size = dest->full;
+ dest->start = (stacktraceelement *) (dest + 1);
+
+ return true;
}
-void cacao_stacktrace_NormalTrace(void **target)
+bool cacao_stacktrace_NormalTrace(void **target)
{
- cacao_stacktrace_fillInStackTrace(target, &stackTraceCollector);
+ return cacao_stacktrace_fillInStackTrace(target, &stackTraceCollector);
}
-static void classContextCollector(void **target, stackTraceBuffer *buffer)
+static bool classContextCollector(void **target, stackTraceBuffer *buffer)
{
- java_objectarray *tmpArray;
+ java_objectarray *oa;
stacktraceelement *current;
stacktraceelement *start;
size_t size;
targetSize--;
if (targetSize > 0) {
- if (start->method && (start->method->class == class_java_lang_SecurityManager)) {
+ if (start->method &&
+ (start->method->class == class_java_lang_SecurityManager)) {
targetSize--;
start++;
}
}
- tmpArray = builtin_anewarray(targetSize, class_java_lang_Class);
+ oa = builtin_anewarray(targetSize, class_java_lang_Class);
- for(i = 0, current = start; i < targetSize; i++, current++) {
- /* XXX TWISTI: should we use this skipping for native stubs? */
+ if (!oa)
+ return false;
+ for(i = 0, current = start; i < targetSize; i++, current++) {
if (!current->method) {
i--;
continue;
use_class_as_object(current->method->class);
- tmpArray->data[i] = (java_objectheader *) current->method->class;
+ oa->data[i] = (java_objectheader *) current->method->class;
}
- *target = tmpArray;
+ *target = oa;
+
+ return true;
}
java_objectarray *cacao_createClassContextArray(void)
{
- java_objectarray *array=0;
+ java_objectarray *array = NULL;
- cacao_stacktrace_fillInStackTrace((void **) &array, &classContextCollector);
+ if (!cacao_stacktrace_fillInStackTrace((void **) &array,
+ &classContextCollector))
+ return NULL;
return array;
}
*******************************************************************************/
-static void stacktrace_classLoaderCollector(void **target,
+static bool stacktrace_classLoaderCollector(void **target,
stackTraceBuffer *buffer)
{
stacktraceelement *current;
if (m->class == class_java_security_PrivilegedAction) {
*target = NULL;
- return;
+ return true;
}
if (m->class->classloader) {
*target = (java_lang_ClassLoader *) m->class->classloader;
- return;
+ return true;
}
}
*target = NULL;
+
+ return true;
}
java_objectheader *cacao_currentClassLoader(void)
{
- java_objectheader *header=0;
+ java_objectheader *header = NULL;
- cacao_stacktrace_fillInStackTrace((void**)&header,
- &stacktrace_classLoaderCollector);
+ if (!cacao_stacktrace_fillInStackTrace((void**)&header,
+ &stacktrace_classLoaderCollector))
+ return NULL;
return header;
}
-static
-void callingMethodCollector(void **target, stackTraceBuffer *buffer) {
- if (buffer->full >2) (*target)=buffer->start[2].method;
- else (*target=0);
-}
-
-methodinfo *cacao_callingMethod() {
- methodinfo *method;
- cacao_stacktrace_fillInStackTrace((void**)&method,&callingMethodCollector);
- return method;
-}
-
-
-static
-void getStackCollector(void **target, stackTraceBuffer *buffer)
+static bool getStackCollector(void **target, stackTraceBuffer *buffer)
{
- java_objectarray *classes;
- java_objectarray *methodnames;
- java_objectarray **result=(java_objectarray**)target;
- java_lang_String *str;
- classinfo *c;
+ java_objectarray *oa;
+ java_objectarray *classes;
+ java_objectarray *methodnames;
+ java_lang_String *str;
+ classinfo *c;
stacktraceelement *current;
- int i,size;
+ s4 i, size;
- /*log_text("getStackCollector");*/
+/* *result = (java_objectarray **) target; */
size = buffer->full;
- *result = builtin_anewarray(2, arrayclass_java_lang_Object);
+ oa = builtin_anewarray(2, arrayclass_java_lang_Object);
- if (!(*result))
- return;
+ if (!oa)
+ return false;
classes = builtin_anewarray(size, class_java_lang_Class);
if (!classes)
- return;
+ return false;
methodnames = builtin_anewarray(size, class_java_lang_String);
if (!methodnames)
- return;
+ return false;
- (*result)->data[0] = (java_objectheader *) classes;
- (*result)->data[1] = (java_objectheader *) methodnames;
+ oa->data[0] = (java_objectheader *) classes;
+ oa->data[1] = (java_objectheader *) methodnames;
- /*log_text("Before for loop");*/
for (i = 0, current = &(buffer->start[0]); i < size; i++, current++) {
- /*log_text("In loop");*/
c = current->method->class;
+
use_class_as_object(c);
+
classes->data[i] = (java_objectheader *) c;
str = javastring_new(current->method->name);
+
if (!str)
- return;
+ return false;
+
methodnames->data[i] = (java_objectheader *) str;
- /*printf("getStackCollector: %s.%s\n",c->name->text,current->method->name->text);*/
}
- /*if (*exceptionptr) panic("Exception in getStackCollector");*/
-
- /*log_text("loop left");*/
- return;
+ *target = oa;
+ return true;
}
{
java_objectarray *result = NULL;
- cacao_stacktrace_fillInStackTrace((void **) &result, &getStackCollector);
+ if (!cacao_stacktrace_fillInStackTrace((void **) &result,
+ &getStackCollector))
+ return NULL;
return result;
}
void stacktrace_dump_trace(void)
{
stackTraceBuffer *buffer;
- stacktraceelement *element;
- methodinfo *m;
- s4 i;
#if 0
/* get thread stackframeinfo */
/* print stacktrace */
if (buffer) {
- element = buffer->start;
+ stacktrace_print_trace(buffer);
- for (i = 0; i < buffer->size; i++, element++) {
- m = element->method;
+ } else {
+ puts("\t<<No stacktrace available>>");
+ fflush(stdout);
+ }
+}
- printf("\tat ");
- utf_display_classname(m->class->name);
- printf(".");
- utf_display(m->name);
- utf_display(m->descriptor);
- if (m->flags & ACC_NATIVE) {
- printf("(Native Method)\n");
+/* stacktrace_print_trace ******************************************************
- } else {
- printf("(");
- utf_display(m->class->sourcefile);
- printf(":%d)\n", (u4) element->linenumber);
- }
+ Print the stacktrace of a given stackTraceBuffer with CACAO intern
+ methods (no Java help). This method is used by
+ stacktrace_dump_trace and builtin_trace_exception.
+
+*******************************************************************************/
+
+void stacktrace_print_trace(stackTraceBuffer *stb)
+{
+ stacktraceelement *ste;
+ methodinfo *m;
+ s4 i;
+
+ ste = stb->start;
+
+ for (i = 0; i < stb->size; i++, ste++) {
+ m = ste->method;
+
+ printf("\tat ");
+ utf_display_classname(m->class->name);
+ printf(".");
+ utf_display(m->name);
+ utf_display(m->descriptor);
+
+ if (m->flags & ACC_NATIVE) {
+ puts("(Native Method)");
+
+ } else {
+ printf("(");
+ utf_display(m->class->sourcefile);
+ printf(":%d)\n", (u4) ste->linenumber);
}
}
- /* flush stdout */
+ /* just to be sure */
fflush(stdout);
}