-/* 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 2954 2005-07-09 13:49:50Z twisti $
+ $Id: stacktrace.c 3570 2005-11-04 16:58:36Z motse $
*/
#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"
+#include "vm/jit/methodheader.h"
-#undef JWDEBUG
-#undef JWDEBUG2
-#undef JWDEBUG3
+/* lineNumberTableEntry *******************************************************/
-/*JoWenn: simplify collectors (trace doesn't contain internal methods)*/
-
-/* the line number is only u2, but to avoid alignment problems it is made the same size as a native
- pointer. In the structures where this is used, values of -1 or -2 have a special meainging, so
- if java bytecode is ever extended to support more than 65535 lines/file, this could will have to
- be changed.*/
-
-#if defined(_ALPHA_) || defined(__X86_64__)
- #define LineNumber u8
-#else
- #define LineNumber u4
-#endif
+/* Keep the type of line the same as the pointer type, otherwise we run into */
+/* alignment troubles (like on MIPS64). */
typedef struct lineNumberTableEntry {
-/* The special value of -1 means that a inlined function starts, a value of -2 means that an inlined function ends*/
- LineNumber lineNr;
- u1 *pc;
+ ptrint line;
+ u1 *pc;
} lineNumberTableEntry;
+
typedef struct lineNumberTableEntryInlineBegin {
-/*this should have the same layout and size as the lineNumberTableEntry*/
- LineNumber lineNrOuter;
+ /* this should have the same layout and size as the lineNumberTableEntry */
+ ptrint lineNrOuter;
methodinfo *method;
} lineNumberTableEntryInlineBegin;
-
-typedef void(*CacaoStackTraceCollector)(void **,stackTraceBuffer*);
+#ifndef ENABLE_JVMTI
+typedef bool(*CacaoStackTraceCollector)(void **, stackTraceBuffer*);
+#endif
#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.
+ Creates an stackframe info structure for an inline exception stub.
*******************************************************************************/
void stacktrace_create_inline_stackframeinfo(stackframeinfo *sfi, u1 *pv,
- u1 *sp, functionptr ra)
+ u1 *sp, functionptr ra,
+ functionptr xpc)
+{
+ stackframeinfo **psfi;
+
+ /* get current stackframe info pointer */
+
+ 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->prev = *psfi;
+ sfi->method = NULL;
+ sfi->pv = pv;
+ sfi->sp = sp;
+ sfi->ra = ra;
+ sfi->xpc = xpc;
+
+ /* store new stackframe info pointer */
+
+ *psfi = sfi;
+}
+
+
+/* stacktrace_create_extern_stackframeinfo *************************************
+
+ Creates an stackframe info structure for an extern exception
+ (hardware or assembler).
+
+*******************************************************************************/
+
+void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
+ u1 *sp, functionptr ra,
+ functionptr xpc)
{
- void **osfi;
+ stackframeinfo **psfi;
+#if !defined(__I386__) && !defined(__X86_64__)
+ bool isleafmethod;
+#endif
+ s4 framesize;
/* get current stackframe info pointer */
- osfi = builtin_asm_get_stackframeinfo();
+ psfi = STACKFRAMEINFO;
-#if defined(__I386__) || defined(__X86_64__)
- /* we don't have pv in asm_wrapper_patcher handy */
+ /* 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 *) codegen_findmethod(ra);
+ pv = (u1 *) (ptrint) codegen_findmethod(ra);
+
+#if defined(ENABLE_INTRP)
+ /* When using the interpreter, we pass RA to the function. */
+
+ 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. */
+
+ 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->beginOfJavaStackframe = sp;
- sfi->returnToFromNative = ra;
+ sfi->sp = sp;
+ sfi->ra = ra;
+ sfi->xpc = xpc;
/* 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->beginOfJavaStackframe = sp;
- sfi->returnToFromNative = ra;
+ sfi->sp = sp;
+ sfi->ra = ra;
+ sfi->xpc = NULL;
/* 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_call_fillInStackTrace ********************************************
+/* stacktrace_inline_arithmeticexception ***************************************
+
+ Creates an ArithemticException for inline stub.
+
+*******************************************************************************/
+
+java_objectheader *stacktrace_inline_arithmeticexception(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_arithmeticexception();
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ return o;
+}
+
+
+/* stacktrace_inline_arrayindexoutofboundsexception ****************************
+
+ Creates an ArrayIndexOutOfBoundsException for inline stub.
+
+*******************************************************************************/
+
+java_objectheader *stacktrace_inline_arrayindexoutofboundsexception(u1 *pv,
+ u1 *sp,
+ functionptr ra,
+ functionptr xpc,
+ s4 index)
+{
+ stackframeinfo sfi;
+ java_objectheader *o;
+
+ /* create stackframeinfo */
+
+ stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+ /* create exception */
+
+ o = new_arrayindexoutofboundsexception(index);
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ return o;
+}
+
+
+/* stacktrace_inline_arraystoreexception ***************************************
+
+ Creates an ArrayStoreException for inline stub.
+
+*******************************************************************************/
+
+java_objectheader *stacktrace_inline_arraystoreexception(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_arraystoreexception();
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ return o;
+}
+
+
+/* stacktrace_inline_classcastexception ****************************************
+
+ Creates an ClassCastException for inline stub.
+
+*******************************************************************************/
+
+java_objectheader *stacktrace_inline_classcastexception(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_classcastexception();
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ return o;
+}
+
+
+/* stacktrace_inline_nullpointerexception **************************************
+
+ Creates an NullPointerException for inline stub.
+
+*******************************************************************************/
+
+java_objectheader *stacktrace_inline_nullpointerexception(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_nullpointerexception();
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ return o;
+}
+
+
+/* stacktrace_hardware_arithmeticexception *************************************
+
+ Creates an ArithemticException for inline stub.
+
+*******************************************************************************/
+
+java_objectheader *stacktrace_hardware_arithmeticexception(u1 *pv, u1 *sp,
+ functionptr ra,
+ functionptr xpc)
+{
+ stackframeinfo sfi;
+ java_objectheader *o;
+
+ /* create stackframeinfo */
+
+ stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+ /* create exception */
+
+ o = new_arithmeticexception();
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ return o;
+}
+
+
+/* stacktrace_hardware_nullpointerexception ************************************
+
+ Creates an NullPointerException for the SIGSEGV signal handler.
+
+*******************************************************************************/
+
+java_objectheader *stacktrace_hardware_nullpointerexception(u1 *pv, u1 *sp,
+ functionptr ra,
+ functionptr xpc)
+{
+ stackframeinfo sfi;
+ java_objectheader *o;
+
+ /* create stackframeinfo */
+
+ stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+ /* create exception */
+
+ o = new_nullpointerexception();
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ return o;
+}
- XXX
+
+/* stacktrace_inline_fillInStackTrace ******************************************
+
+ Fills in the correct stacktrace into an existing exception object
+ (this one is for inline exception stubs).
*******************************************************************************/
-void stacktrace_call_fillInStackTrace(java_objectheader *o)
+java_objectheader *stacktrace_inline_fillInStackTrace(u1 *pv, u1 *sp,
+ functionptr ra,
+ functionptr xpc)
{
- methodinfo *m;
+ stackframeinfo sfi;
+ java_objectheader *o;
+ methodinfo *m;
+
+ /* create stackframeinfo */
+
+ stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+ /* get exception */
+
+ o = *exceptionptr;
+
+ /* clear exception */
+
+ *exceptionptr = NULL;
/* resolve methodinfo pointer from exception object */
/* call function */
asm_calljavafunction(m, o, NULL, NULL, NULL);
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ return o;
}
-static void addEntry(stackTraceBuffer* buffer,methodinfo*method ,LineNumber line) {
- if (buffer->size>buffer->full) {
- stacktraceelement *tmp=&(buffer->start[buffer->full]);
- tmp->method=method;
- tmp->linenumber=line;
+/* addEntry ********************************************************************
+
+ XXX
+
+*******************************************************************************/
+
+static void addEntry(stackTraceBuffer *buffer, methodinfo *method, u2 line)
+{
+ if (buffer->size > buffer->full) {
+ stacktraceelement *tmp = &(buffer->start[buffer->full]);
+
+ tmp->method = method;
+ tmp->linenumber = line;
buffer->full = buffer->full + 1;
-#if (defined(JWDEBUG) || defined (JWDEBUG2))
- log_text("addEntry (stacktrace):");
- printf("method %p\n",method);
- if (method) printf("method->name %p\n",method->name);
- if (method) utf_display(method->name); else printf("Native");
- if (method) {printf("\n");utf_display(method->class->name);}
- printf("\nnext buffer item %d\nLine:%ld\n",buffer->full,line);
-#endif
+
} else {
stacktraceelement *newBuffer;
-#ifdef JWDEBUG
- log_text("stacktrace buffer full, resizing");
-#endif
-
newBuffer =
(stacktraceelement *) malloc((buffer->size + BLOCK_SIZEINCREMENT) *
sizeof(stacktraceelement));
- if (newBuffer==0) {
+ if (newBuffer == 0) {
log_text("OOM during stacktrace creation");
assert(0);
}
- memcpy(newBuffer,buffer->start,buffer->size*sizeof(stacktraceelement));
- if (buffer->needsFree) free(buffer->start);
- buffer->start=newBuffer;
- buffer->size=buffer->size+BLOCK_SIZEINCREMENT;
- buffer->needsFree=1;
- addEntry(buffer,method,line);
+ memcpy(newBuffer, buffer->start, buffer->size * sizeof(stacktraceelement));
+ if (buffer->needsFree)
+ free(buffer->start);
+
+ buffer->start = newBuffer;
+ buffer->size = buffer->size + BLOCK_SIZEINCREMENT;
+ buffer->needsFree = 1;
+
+ addEntry(buffer, method, line);
}
}
*******************************************************************************/
-static int stacktrace_fillInStackTrace_methodRecursive(stackTraceBuffer *buffer,
- methodinfo *method,
- lineNumberTableEntry *startEntry,
- lineNumberTableEntry **entry,
- size_t *entriesAhead,
- u1 *address)
+static bool stacktrace_fillInStackTrace_methodRecursive(stackTraceBuffer *buffer,
+ methodinfo *m,
+ lineNumberTableEntry *lntentry,
+ s4 lntsize,
+ u1 *pc)
{
+#if 0
+ lineNumberTableEntryInlineBegin *lntinline;
+#endif
+
+ /* find the line number for the specified pc (going backwards) */
+
+ for (; lntsize > 0; lntsize--, lntentry--) {
+ /* did we reach the current line? */
- size_t ahead=*entriesAhead;
- lineNumberTableEntry *ent=*entry;
- lineNumberTableEntryInlineBegin *ilStart;
+ if (pc >= lntentry->pc) {
+ /* check for special inline entries */
+
+ switch (lntentry->line) {
+#if 0
+ /* XXX TWISTI we have to think about this inline stuff again */
- for (; ahead > 0; ahead--, ent++) {
- if (address >= ent->pc) {
- switch (ent->lineNr) {
case -1: /* begin of inlined method */
- ilStart=(lineNumberTableEntryInlineBegin*)(++ent);
- ent ++;
- ahead--; ahead--;
- if (stacktrace_fillInStackTrace_methodRecursive(buffer,ilStart->method,ent,&ent,&ahead,address)) {
- addEntry(buffer,method,ilStart->lineNrOuter);
- return 1;
+ lntinline = (lineNumberTableEntryInlineBegin *) (--lntentry);
+ lntentry++;
+ lntsize--; lntsize--;
+ if (stacktrace_fillInStackTrace_methodRecursive(buffer,
+ ilStart->method,
+ ent,
+ &ent,
+ &ahead,
+ pc)) {
+ addEntry(buffer, m, ilStart->lineNrOuter);
+
+ return true;
}
break;
+
case -2: /* end of inlined method */
- *entry=ent;
- *entriesAhead=ahead;
- return 0;
+ *entry = ent;
+ *entriesAhead = ahead;
+ return false;
break;
+#endif
+
default:
- if (address == ent->pc) {
- addEntry(buffer, method, ent->lineNr);
- return 1;
- }
- break;
+ addEntry(buffer, m, lntentry->line);
+ return true;
}
+ }
+ }
- } else {
- if (address > startEntry->pc) {
- ent--;
- addEntry(buffer, method, ent->lineNr);
- return 1;
+ /* check if we are before the actual JIT code */
- } else {
- printf("trace point: %p\n", address);
- log_text("trace point before method");
- assert(0);
- }
- }
+ if ((ptrint) pc < (ptrint) m->entrypoint) {
+ dolog("Current pc before start of code: %p < %p", pc, m->entrypoint);
+ assert(0);
}
- ent--;
- addEntry(buffer, method, ent->lineNr);
- return 1;
+ /* otherwise just add line 0 */
+
+ addEntry(buffer, m, 0);
+
+ return true;
}
*******************************************************************************/
static void stacktrace_fillInStackTrace_method(stackTraceBuffer *buffer,
- methodinfo *method, u1 *dataSeg,
- u1 *address)
+ methodinfo *method, u1 *pv,
+ u1 *pc)
{
- size_t lineNumberTableSize=(*((size_t*)(dataSeg+LineNumberTableSize)));
- lineNumberTableEntry *ent;
- void **calc;
- lineNumberTableEntry *startEntry;
+ ptrint lntsize; /* size of line number table */
+ u1 *lntstart; /* start of line number table */
+ lineNumberTableEntry *lntentry; /* points to last entry in the table */
- if (lineNumberTableSize == 0) {
- /* right now this happens only on i386,if the native stub causes an */
- /* exception in a <clinit> invocation (jowenn) */
+ /* get size of line number table */
- addEntry(buffer, method, 0);
- return;
+ lntsize = *((ptrint *) (pv + LineNumberTableSize));
+ lntstart = *((u1 **) (pv + LineNumberTableStart));
- } else {
- calc = (void **) (dataSeg + LineNumberTableStart);
- ent = (lineNumberTableEntry *) (((char *) (*calc) - (sizeof(lineNumberTableEntry) - SIZEOF_VOID_P)));
+ /* subtract the size of the line number entry of the structure, since the */
+ /* line number table start points to the pc */
+
+ lntentry = (lineNumberTableEntry *) (lntstart - SIZEOF_VOID_P);
+
+ if (lntsize == 0) {
+ /* this happens when an exception is thrown in the native stub */
- ent -= (lineNumberTableSize - 1);
- startEntry = ent;
+ addEntry(buffer, method, 0);
- if (!stacktrace_fillInStackTrace_methodRecursive(buffer, method,
- startEntry, &ent,
- &lineNumberTableSize,
- address)) {
+ } else {
+ if (!stacktrace_fillInStackTrace_methodRecursive(buffer,
+ method,
+ lntentry,
+ lntsize,
+ pc)) {
log_text("Trace point not found in suspected method");
assert(0);
}
XXX
*******************************************************************************/
-
-void cacao_stacktrace_fillInStackTrace(void **target,
+#ifdef ENABLE_JVMTI
+bool cacao_stacktrace_fillInStackTrace(void **target,
+ CacaoStackTraceCollector coll,
+ threadobject* thread)
+#else
+static bool cacao_stacktrace_fillInStackTrace(void **target,
CacaoStackTraceCollector coll)
+#endif
+
{
- stacktraceelement primaryBlock[BLOCK_INITIALSIZE*sizeof(stacktraceelement)];
+ 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 */
+
+ pv = NULL;
+ sp = NULL;
+ ra = NULL;
/* In most cases this should be enough -> one malloc less. I don't think */
/* temporary data should be allocated with the GC, only the result. */
buffer.size = BLOCK_INITIALSIZE; /* *sizeof(stacktraceelement); */
buffer.full = 0;
- info = *((void **) builtin_asm_get_stackframeinfo());
+ /* the first element in the stackframe chain must always be a native */
+ /* stackframeinfo (VMThrowable.fillInStackTrace is a native function) */
- if (!info) {
+#ifdef ENABLE_JVMTI
+ if (thread == NULL)
+ sfi = *STACKFRAMEINFO; /* invocation from Throwable */
+ else
+ sfi = thread->info._stackframeinfo; /* invocation from JVMTI */
+#else
+ sfi = *STACKFRAMEINFO;
+#endif
+
+ if (!sfi) {
*target = NULL;
- return;
+ return true;
+ }
- } else {
- m = NULL;
+#define PRINTMETHODS 0
- while (m || info) {
- /* some builtin native */
+#if PRINTMETHODS
+ printf("\n\nfillInStackTrace start:\n");
+ fflush(stdout);
+#endif
- if (m == NULL) {
- m = info->method;
- ra = (functionptr) info->returnToFromNative;
+ /* loop while we have a method pointer (asm_calljavafunction has NULL) or */
+ /* there is a stackframeinfo in the chain */
-#if 0
- if (m) {
+ m = NULL;
+
+ 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 (sfi->pv == NULL) {
+ /* get methodinfo, sp and ra from the current stackframe info */
+
+ m = sfi->method;
+ sp = sfi->sp; /* sp of parent Java function */
+ ra = sfi->ra;
+
+ if (m)
+ addEntry(&buffer, m, 0);
+
+#if PRINTMETHODS
+ utf_display_classname(m->class->name);
+ printf(".");
+ 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*) */
+
+ pv = (u1 *) (ptrint) codegen_findmethod(ra);
+
+ /* get methodinfo pointer from parent data segment */
+
+ m = *((methodinfo **) (pv + MethodPointer));
+
+ } else {
+ /* Inline stackframe infos are special: they have a xpc of */
+ /* the actual exception position and the return address saved */
+ /* since an inline stackframe info can also be in a leaf */
+ /* method (no return address saved on stack!!!). */
+ /* ATTENTION: This one is also for hardware exceptions!!! */
+
+ /* get methodinfo, sp and ra from the current stackframe info */
+
+ 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 */
+
+ m = *((methodinfo **) (pv + MethodPointer));
+
+ /* 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(": native\n");
+ printf(": inline stub parent\n");
+ fflush(stdout);
+#endif
- addEntry(&buffer, m, 0);
- } else {
- printf("NULL: native\n");
- }
-#else
- if (m) {
- addEntry(&buffer, m, 0);
- }
+#if defined(ENABLE_INTRP)
+ if (!opt_intrp) {
#endif
- /* get data segment address */
+ /* add it to the stacktrace */
- if (info->pv) {
- /* this is an inline info */
+ stacktrace_fillInStackTrace_method(&buffer, m, pv,
+ (u1 *) ((ptrint) xpc));
- pv = info->pv;
+ /* get the current stack frame size */
- } else {
- /* this is an native stub info */
+ framesize = *((u4 *) (pv + FrameSize));
- pv = (u1 *) codegen_findmethod(ra);
- }
+ /* set stack pointer to stackframe of parent Java */
+ /* function of the current Java function */
- /* get methodinfo pointer from data segment */
+#if defined(__I386__) || defined (__X86_64__)
+ sp += framesize + SIZEOF_VOID_P;
+#else
+ sp += framesize;
+#endif
- m = *((methodinfo **) (pv + MethodPointer));
+ /* get data segment and methodinfo pointer from parent */
+ /* method */
- /* get stackpointer from stackframeinfo structure */
+ pv = (u1 *) (ptrint) codegen_findmethod(ra);
+ m = *((methodinfo **) (pv + MethodPointer));
- sp = (u1 *) info->beginOfJavaStackframe;
+#if defined(ENABLE_INTRP)
+ }
+#endif
+ }
+#if PRINTMETHODS
+ else {
+ printf("asm_calljavafunction\n");
+ fflush(stdout);
+ }
+#endif
+ }
- info = info->oldThreadspecificHeadValue;
+ /* get previous stackframeinfo in the chain */
- } else {
- /* JIT method */
+ sfi = sfi->prev;
-#if 0
- utf_display_classname(m->class->name);
- printf(".");
- utf_display(m->name);
- utf_display(m->descriptor);
- printf(": JIT\n");
+ } else {
+#if PRINTMETHODS
+ utf_display_classname(m->class->name);
+ printf(".");
+ utf_display(m->name);
+ utf_display(m->descriptor);
+ printf(": JIT\n");
#endif
- /* add the current method to the stacktrace */
+ /* JIT method found, add it to the stacktrace (we subtract 1 from */
+ /* the return address since it points the the instruction after */
+ /* call) */
- stacktrace_fillInStackTrace_method(&buffer, m, pv,
- ((u1 *) ra) - 1);
+ stacktrace_fillInStackTrace_method(&buffer, m, pv,
+ (u1 *) ((ptrint) ra) - 1);
- /* get the current stack frame size */
+ /* get the current stack frame size */
- framesize = *((u4 *) (pv + FrameSize));
+ framesize = *((u4 *) (pv + FrameSize));
- /* get return address of current stack frame */
+ /* get return address of current stack frame */
- ra = md_stacktrace_get_returnaddress(sp, framesize);
+ ra = md_stacktrace_get_returnaddress(sp, framesize);
- /* get data segment and methodinfo pointer from parent method */
+ /* get data segment and methodinfo pointer from parent method */
- pv = (u1 *) codegen_findmethod(ra);
- m = *((methodinfo **) (pv + MethodPointer));
+ pv = (u1 *) (ptrint) codegen_findmethod(ra);
+ m = *((methodinfo **) (pv + MethodPointer));
- /* walk the stack */
+ /* 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);
+ if (coll)
+ result = coll(target, &buffer);
- if (buffer.needsFree)
- free(buffer.start);
+ if (buffer.needsFree)
+ free(buffer.start);
- return;
- }
-
- *target = NULL;
+ 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 *********************************************************
+
+ XXX
+
+*******************************************************************************/
+#ifdef ENABLE_JVMTI
+bool stackTraceCollector(void **target, stackTraceBuffer *buffer)
+#else
+static bool stackTraceCollector(void **target, stackTraceBuffer *buffer)
+#endif
+{
+ stackTraceBuffer *dest;
- dest->needsFree=0;
- dest->size=dest->full;
- dest->start=(stacktraceelement*)(dest+1);
+ 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);
+#ifdef ENABLE_JVMTI
+ return cacao_stacktrace_fillInStackTrace(target, &stackTraceCollector, NULL);
+#else
+ return cacao_stacktrace_fillInStackTrace(target, &stackTraceCollector);
+#endif
+
}
-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);
+#ifdef ENABLE_JVMTI
+ if (!cacao_stacktrace_fillInStackTrace((void **) &array,
+ &classContextCollector, NULL))
+#else
+ if (!cacao_stacktrace_fillInStackTrace((void **) &array,
+ &classContextCollector))
+#endif
+ 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;
-
- cacao_stacktrace_fillInStackTrace((void**)&header,
- &stacktrace_classLoaderCollector);
-
- return header;
-}
+ java_objectheader *header = NULL;
-static
-void callingMethodCollector(void **target, stackTraceBuffer *buffer) {
- if (buffer->full >2) (*target)=buffer->start[2].method;
- else (*target=0);
-}
+#ifdef ENABLE_JVMTI
+ if (!cacao_stacktrace_fillInStackTrace((void**)&header,
+ &stacktrace_classLoaderCollector,
+ NULL))
+#else
+ if (!cacao_stacktrace_fillInStackTrace((void**)&header,
+ &stacktrace_classLoaderCollector))
+#endif
+ return NULL;
-methodinfo *cacao_callingMethod() {
- methodinfo *method;
- cacao_stacktrace_fillInStackTrace((void**)&method,&callingMethodCollector);
- return method;
+ return header;
}
-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);
+#ifdef ENABLE_JVMTI
+ if (!cacao_stacktrace_fillInStackTrace((void **) &result,
+ &getStackCollector,NULL))
+#else
+ if (!cacao_stacktrace_fillInStackTrace((void **) &result,
+ &getStackCollector))
+#endif
+ return NULL;
return result;
}
void stacktrace_dump_trace(void)
{
stackTraceBuffer *buffer;
- stacktraceelement *element;
- methodinfo *m;
- s4 i;
#if 0
/* get thread stackframeinfo */
tmp.oldThreadspecificHeadValue = *info;
tmp.addressOfThreadspecificHead = info;
tmp.method = NULL;
- tmp.beginOfJavaStackframe = NULL;
- tmp.returnToFromNative = _mc->gregs[REG_RIP];
+ tmp.sp = NULL;
+ tmp.ra = _mc->gregs[REG_RIP];
*info = &tmp;
#endif
/* 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);
}