-/* src/vm/jit/stacktrace.c
+/* src/vm/jit/stacktrace.c - machine independent stacktrace system
- Copyright (C) 1996-2005 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 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
This file is part of CACAO.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
- Contact: cacao@complang.tuwien.ac.at
-
- Authors: Joseph Wenninger
-
- Changes: Christian Thalinger
-
- $Id: stacktrace.c 2933 2005-07-08 11:59:57Z twisti $
+ $Id: stacktrace.c 7584 2007-03-27 18:17:27Z tbfg $
*/
+#include "config.h"
+
#include <assert.h>
#include <stdlib.h>
#include <string.h>
-#include "config.h"
-#include "asmoffsets.h"
+#include "vm/types.h"
+
+#include "mm/gc-common.h"
+#include "mm/memory.h"
-#include "mm/boehm.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"
+
+#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/stringlocal.h"
-#include "vm/tables.h"
+#include "vm/vm.h"
+
#include "vm/jit/asmpart.h"
-#include "vm/jit/codegen.inc.h"
+#include "vm/jit/codegen-common.h"
+#include "vm/jit/methodheader.h"
+#include "vmcore/class.h"
+#include "vmcore/loader.h"
+#include "vmcore/options.h"
-#undef JWDEBUG
-#undef JWDEBUG2
-#undef JWDEBUG3
-/*JoWenn: simplify collectors (trace doesn't contain internal methods)*/
+/* global variables ***********************************************************/
+#if !defined(ENABLE_THREADS)
+stackframeinfo *_no_threads_stackframeinfo = NULL;
+#endif
-/* 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.*/
+CYCLES_STATS_DECLARE(stacktrace_overhead ,100,1)
+CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace,40,5000)
+CYCLES_STATS_DECLARE(stacktrace_getClassContext ,40,5000)
+CYCLES_STATS_DECLARE(stacktrace_getCurrentClass ,40,5000)
+CYCLES_STATS_DECLARE(stacktrace_getStack ,40,10000)
-#if defined(_ALPHA_) || defined(__X86_64__)
- #define LineNumber u8
-#else
- #define LineNumber u4
+
+/* 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,
+ u1 *ra)
+{
+ stackframeinfo **psfi;
+ methodinfo *m;
+ codeinfo *code;
+
+ /* get current stackframe info pointer */
+
+ psfi = STACKFRAMEINFO;
+
+ /* if we don't have pv handy */
+
+ if (pv == NULL) {
+#if defined(ENABLE_INTRP)
+ if (opt_intrp)
+ pv = codegen_get_pv_from_pc(ra);
+ else
+#endif
+ {
+#if defined(ENABLE_JIT)
+ pv = md_codegen_get_pv_from_pc(ra);
#endif
+ }
+ }
+
+ /* get codeinfo pointer from data segment */
-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;
-} lineNumberTableEntry;
+ 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 */
+
+ sfi->prev = *psfi;
+ sfi->method = m;
+ sfi->pv = pv;
+ sfi->sp = sp;
+ sfi->ra = ra;
-typedef struct lineNumberTableEntryInlineBegin {
-/*this should have the same layout and size as the lineNumberTableEntry*/
- LineNumber lineNrOuter;
- methodinfo *method;
-} lineNumberTableEntryInlineBegin;
+ /* xpc is the same as ra, but is required in stacktrace_create */
+ sfi->xpc = ra;
-typedef void(*CacaoStackTraceCollector)(void **,stackTraceBuffer*);
+ /* store new stackframe info pointer */
-#define BLOCK_INITIALSIZE 40
-#define BLOCK_SIZEINCREMENT 40
+ *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, u1 *ra, u1 *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 = codegen_get_pv_from_pc(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, u1 *ra, u1 *xpc)
{
- void **osfi;
+ stackframeinfo **psfi;
+#if !defined(__I386__) && !defined(__X86_64__) && !defined(__S390__)
+ bool isleafmethod;
+#endif
+#if defined(ENABLE_JIT)
+ s4 framesize;
+#endif
/* 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 or in the interpreter). */
+
+ if (pv == NULL) {
+#if defined(ENABLE_INTRP)
+ if (opt_intrp)
+ pv = codegen_get_pv_from_pc(ra);
+ else
+#endif
+ {
+#if defined(ENABLE_JIT)
+# if defined(__SPARC_64__)
+ pv = md_get_pv_from_stackframe(sp);
+# else
+ pv = md_codegen_get_pv_from_pc(ra);
+# endif
+#endif
+ }
+ }
+
+#if defined(ENABLE_JIT)
+# if defined(ENABLE_INTRP)
+ /* When using the interpreter, we pass RA to the function. */
+
+ if (!opt_intrp) {
+# endif
+# 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));
+
+ 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
+#endif /* defined(ENABLE_JIT) */
/* 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->pv = pv;
+ 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)
+ u1 *sp, u1 *ra)
{
- void **osfi;
- methodinfo *m;
+ stackframeinfo **psfi;
+ methodinfo *m;
+ codeinfo *code;
+
+ /* get codeinfo pointer from data segment */
- /* get methodinfo 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;
/* 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->pv = NULL;
+ sfi->sp = sp;
+ sfi->ra = ra;
+ sfi->xpc = NULL;
/* store new stackframe info pointer */
- *osfi = sfi;
+ *psfi = sfi;
}
/* stacktrace_remove_stackframeinfo ********************************************
- XXX
+ Remove the topmost stackframeinfo in the current thread.
*******************************************************************************/
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_arithmeticexception ***************************************
+
+ Creates an ArithemticException for inline stub.
+
+*******************************************************************************/
+
+java_objectheader *stacktrace_inline_arithmeticexception(u1 *pv, u1 *sp,
+ u1 *ra, u1 *xpc)
+{
+ stackframeinfo sfi;
+ java_objectheader *o;
+
+ /* create stackframeinfo */
+
+ stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+ /* create exception */
+
+ o = exceptions_new_arithmeticexception();
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ return o;
}
-/* stacktrace_call_fillInStackTrace ********************************************
+/* stacktrace_inline_arrayindexoutofboundsexception ****************************
- XXX
+ Creates an ArrayIndexOutOfBoundsException for inline stub.
*******************************************************************************/
-void stacktrace_call_fillInStackTrace(java_objectheader *o)
+java_objectheader *stacktrace_inline_arrayindexoutofboundsexception(u1 *pv,
+ u1 *sp,
+ u1 *ra,
+ u1 *xpc,
+ s4 index)
{
- methodinfo *m;
+ stackframeinfo sfi;
+ java_objectheader *o;
+
+ /* create stackframeinfo */
+
+ stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+ /* create exception */
+
+ o = exceptions_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, u1 *ra,
+ u1 *xpc)
+{
+ stackframeinfo sfi;
+ java_objectheader *o;
+
+ /* create stackframeinfo */
+
+ stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+ /* create exception */
+
+ o = exceptions_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, u1 *ra,
+ u1 *xpc,
+ java_objectheader *o)
+{
+ stackframeinfo sfi;
+ java_objectheader *e;
+
+ /* create stackframeinfo */
+
+ stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+ /* create exception */
+
+ e = exceptions_new_classcastexception(o);
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ return e;
+}
+
+
+/* stacktrace_inline_nullpointerexception **************************************
+
+ Creates an NullPointerException for inline stub.
+
+*******************************************************************************/
+
+java_objectheader *stacktrace_inline_nullpointerexception(u1 *pv, u1 *sp,
+ u1 *ra, u1 *xpc)
+{
+ stackframeinfo sfi;
+ java_objectheader *o;
+
+ /* create stackframeinfo */
+
+ stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+ /* create exception */
+
+ o = exceptions_new_nullpointerexception();
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ return o;
+}
+
+
+/* stacktrace_inline_fillInStackTrace ******************************************
+
+ Fills in the correct stacktrace into an existing exception object
+ (this one is for inline exception stubs).
+
+*******************************************************************************/
+
+java_objectheader *stacktrace_inline_fillInStackTrace(u1 *pv, u1 *sp, u1 *ra,
+ u1 *xpc)
+{
+ stackframeinfo sfi;
+ java_objectheader *o;
+ methodinfo *m;
+
+ /* create stackframeinfo */
+
+ stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+ /* get exception */
+
+ o = *exceptionptr;
+ assert(o);
+
+ /* clear exception */
+
+ *exceptionptr = NULL;
/* 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 */
- asm_calljavafunction(m, o, NULL, NULL, NULL);
+ (void) vm_call_method(m, o);
+
+ /* 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;
- 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;
+/* stacktrace_hardware_arithmeticexception *************************************
-#ifdef JWDEBUG
- log_text("stacktrace buffer full, resizing");
-#endif
+ Creates an ArithemticException for inline stub.
- newBuffer =
- (stacktraceelement *) malloc((buffer->size + BLOCK_SIZEINCREMENT) *
- sizeof(stacktraceelement));
+*******************************************************************************/
- if (newBuffer==0) {
- log_text("OOM during stacktrace creation");
- assert(0);
- }
+java_objectheader *stacktrace_hardware_arithmeticexception(u1 *pv, u1 *sp,
+ u1 *ra, u1 *xpc)
+{
+ stackframeinfo sfi;
+ java_objectheader *o;
- 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);
- }
+ /* create stackframeinfo */
+
+ stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+ /* create exception */
+
+ o = exceptions_new_arithmeticexception();
+
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ return o;
}
-/* stacktrace_fillInStackTrace_methodRecursive *********************************
+/* stacktrace_hardware_nullpointerexception ************************************
- XXX
+ Creates an NullPointerException for the SIGSEGV signal handler.
*******************************************************************************/
-static int stacktrace_fillInStackTrace_methodRecursive(stackTraceBuffer *buffer,
- methodinfo *method,
- lineNumberTableEntry *startEntry,
- lineNumberTableEntry **entry,
- size_t *entriesAhead,
- u1 *address)
+java_objectheader *stacktrace_hardware_nullpointerexception(u1 *pv, u1 *sp,
+ u1 *ra, u1 *xpc)
{
+ stackframeinfo sfi;
+ java_objectheader *o;
- size_t ahead=*entriesAhead;
- lineNumberTableEntry *ent=*entry;
- lineNumberTableEntryInlineBegin *ilStart;
-
- 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;
- }
- break;
- case -2: /* end of inlined method */
- *entry=ent;
- *entriesAhead=ahead;
- return 0;
- break;
- default:
- if (address == ent->pc) {
- addEntry(buffer, method, ent->lineNr);
- return 1;
- }
- break;
- }
+ /* create stackframeinfo */
- } else {
- if (address > startEntry->pc) {
- ent--;
- addEntry(buffer, method, ent->lineNr);
- return 1;
+ stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
- } else {
- printf("trace point: %p\n", address);
- log_text("trace point before method");
- assert(0);
- }
- }
- }
+ /* create exception */
+
+ o = exceptions_new_nullpointerexception();
- ent--;
- addEntry(buffer, method, ent->lineNr);
- return 1;
+ /* remove stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ return o;
}
-/* stacktrace_fillInStackTrace_method ******************************************
+/* stacktrace_add_entry ********************************************************
- XXX
+ Adds a new entry to the stacktrace buffer.
*******************************************************************************/
-static void stacktrace_fillInStackTrace_method(stackTraceBuffer *buffer,
- methodinfo *method, u1 *dataSeg,
- u1 *address)
+static void stacktrace_add_entry(stacktracebuffer *stb, methodinfo *m, u2 line)
{
- size_t lineNumberTableSize=(*((size_t*)(dataSeg+LineNumberTableSize)));
- lineNumberTableEntry *ent;
- void **calc;
- lineNumberTableEntry *startEntry;
+ stacktrace_entry *ste;
- if (lineNumberTableSize == 0) {
- /* right now this happens only on i386,if the native stub causes an */
- /* exception in a <clinit> invocation (jowenn) */
+ /* check if we already reached the buffer capacity */
- addEntry(buffer, method, 0);
- return;
+ if (stb->used >= stb->capacity) {
+ /* reallocate new memory */
- } else {
- calc = (void **) (dataSeg + LineNumberTableStart);
- ent = (lineNumberTableEntry *) (((char *) (*calc) - (sizeof(lineNumberTableEntry) - SIZEOF_VOID_P)));
+ stb->entries = DMREALLOC(stb->entries, stacktrace_entry, stb->capacity,
+ stb->capacity + STACKTRACE_CAPACITY_INCREMENT);
- ent -= (lineNumberTableSize - 1);
- startEntry = ent;
+ /* set new buffer capacity */
- if (!stacktrace_fillInStackTrace_methodRecursive(buffer, method,
- startEntry, &ent,
- &lineNumberTableSize,
- address)) {
- log_text("Trace point not found in suspected method");
- assert(0);
- }
+ stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
}
+
+ /* insert the current entry */
+
+ ste = &(stb->entries[stb->used]);
+
+ ste->method = m;
+ ste->linenumber = line;
+
+ /* increase entries used count */
+
+ stb->used += 1;
}
-/* cacao_stacktrace_fillInStackTrace *******************************************
+/* stacktrace_add_method *******************************************************
+
+ Add stacktrace entries[1] for the given method to the stacktrace buffer.
+
+ IN:
+ stb.........stacktracebuffer to fill
+ m...........method for which entries should be created
+ pv..........pv of method
+ pc..........position of program counter within the method's code
+
+ OUT:
+ true, if stacktrace entries were successfully created, false otherwise.
+
+ [1] In case of inlined methods there may be more than one stacktrace
+ entry for a codegen-level method. (see doc/inlining_stacktrace.txt)
+
+*******************************************************************************/
+
+static bool stacktrace_add_method(stacktracebuffer *stb, methodinfo *m, u1 *pv,
+ u1 *pc)
+{
+ codeinfo *code; /* compiled realization of method */
+ s4 linenumber;
+
+ /* find the realization of the method the pc is in */
+
+ code = *((codeinfo **) (pv + CodeinfoPointer));
+
+ /* search the line number table */
+
+ linenumber = dseg_get_linenumber_from_pc(&m, pv, pc);
+
+ /* now add a new entry to the staktrace */
+
+ stacktrace_add_entry(stb, m, linenumber);
+
+ return true;
+}
+
+
+/* stacktrace_create ***********************************************************
+
+ Generates a stacktrace from the thread passed into a
+ stacktracebuffer. The stacktracebuffer is allocated on the GC
+ heap.
- XXX
+ RETURN VALUE:
+ pointer to the stacktracebuffer, or
+ NULL if an exception has been thrown
*******************************************************************************/
-void cacao_stacktrace_fillInStackTrace(void **target,
- CacaoStackTraceCollector coll)
+stacktracebuffer *stacktrace_create(threadobject* thread)
{
- stacktraceelement primaryBlock[BLOCK_INITIALSIZE*sizeof(stacktraceelement)];
- stackTraceBuffer buffer;
- stackframeinfo *info;
+ stacktracebuffer *stb;
+ stackframeinfo *sfi;
methodinfo *m;
+ codeinfo *code;
u1 *pv;
u1 *sp;
u4 framesize;
- functionptr ra;
+ u1 *ra;
+ u1 *xpc;
+ /* prevent compiler warnings */
- /* 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. */
+ pv = NULL;
+ sp = NULL;
+ ra = NULL;
- buffer.needsFree = 0;
- buffer.start = primaryBlock;
- buffer.size = BLOCK_INITIALSIZE; /* *sizeof(stacktraceelement); */
- buffer.full = 0;
+ /* create a stacktracebuffer in dump memory */
- info = *((void **) builtin_asm_get_stackframeinfo());
+ stb = DNEW(stacktracebuffer);
- if (!info) {
- *target = NULL;
- return;
+ stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
+ stb->used = 0;
+ stb->entries = DMNEW(stacktrace_entry, STACKTRACE_CAPACITY_DEFAULT);
- } else {
- m = NULL;
+ /* The first element in the stackframe chain must always be a
+ native stackframeinfo (VMThrowable.fillInStackTrace is a native
+ function). */
- while (m || info) {
- /* some builtin native */
+ /* We don't use the STACKFRAMEINFO macro here, as we have to use
+ the passed thread. */
- if (m == NULL) {
- m = info->method;
- ra = (functionptr) info->returnToFromNative;
+#if defined(ENABLE_THREADS)
+ sfi = thread->_stackframeinfo;
+#else
+ sfi = _no_threads_stackframeinfo;
+#endif
-#if 0
- if (m) {
- utf_display_classname(m->class->name);
- printf(".");
- utf_display(m->name);
- utf_display(m->descriptor);
- printf(": native\n");
+#define PRINTMETHODS 0
- addEntry(&buffer, m, 0);
- } else {
- printf("NULL: native\n");
- }
-#else
- if (m) {
- addEntry(&buffer, m, 0);
- }
+#if PRINTMETHODS
+ printf("\n\nfillInStackTrace start:\n");
+ fflush(stdout);
#endif
- /* get data segment address */
+ /* Loop while we have a method pointer (asm_calljavafunction has
+ NULL) or there is a stackframeinfo in the chain. */
- if (info->pv) {
- /* this is an inline info */
+ m = NULL;
- pv = info->pv;
+ 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. */
- } else {
- /* this is an native stub info */
+ if (m == NULL) {
+ /* for native stub stackframe infos, pv is always NULL */
- pv = (u1 *) codegen_findmethod(ra);
- }
+ 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)
+ stacktrace_add_entry(stb, m, 0);
+
+#if PRINTMETHODS
+ printf("ra=%p sp=%p, ", ra, sp);
+ method_print(m);
+ 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*). */
+
+#if defined(ENABLE_INTRP)
+ if (opt_intrp)
+ pv = codegen_get_pv_from_pc(ra);
+ else
+#endif
+ {
+#if defined(ENABLE_JIT)
+ pv = md_codegen_get_pv_from_pc(ra);
+#endif
+ }
+
+ /* get methodinfo pointer from parent data segment */
+
+ 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
+ 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("ra=%p sp=%p, ", ra, sp);
+ printf("NULL: inline stub\n");
+ fflush(stdout);
+#endif
+
+ /* get methodinfo from current Java method */
+
+ code = *((codeinfo **) (pv + CodeinfoPointer));
+
+ /* For asm_vm_call_method the codeinfo pointer is
+ NULL. */
- /* get methodinfo pointer from data segment */
+ m = (code == NULL) ? NULL : code->m;
- m = *((methodinfo **) (pv + MethodPointer));
+ /* if m == NULL, this is a asm_calljavafunction call */
- if (info->beginOfJavaStackframe == 0) {
- sp = ((u1 *) info) + sizeof(stackframeinfo);
+ if (m != NULL) {
+#if PRINTMETHODS
+ printf("ra=%p sp=%p, ", ra, sp);
+ method_print(m);
+ printf(": inline stub parent");
+ fflush(stdout);
+#endif
+
+#if defined(ENABLE_INTRP)
+ if (!opt_intrp) {
+#endif
+
+ /* add the method to the stacktrace */
+
+ stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) xpc));
+
+ /* get the current stack frame size */
+
+ framesize = *((u4 *) (pv + FrameSize));
+
+#if PRINTMETHODS
+ printf(", framesize=%d\n", framesize);
+ fflush(stdout);
+#endif
+
+ /* Set stack pointer to stackframe of parent Java
+ function of the current Java function. */
- } else {
#if defined(__I386__) || defined (__X86_64__)
- sp = (u1 *) info->beginOfJavaStackframe + SIZEOF_VOID_P;
+ sp += framesize + SIZEOF_VOID_P;
+#elif defined(__SPARC_64__)
+ sp = md_get_framepointer(sp);
#else
- sp = (u1 *) info->beginOfJavaStackframe;
+ sp += framesize;
+#endif
+
+ /* get data segment and methodinfo pointer from
+ parent method */
+
+#if defined(ENABLE_JIT)
+ pv = md_codegen_get_pv_from_pc(ra);
#endif
+
+ code = *((codeinfo **) (pv + CodeinfoPointer));
+
+ /* For asm_vm_call_method the codeinfo pointer is
+ NULL. */
+
+ m = (code == NULL) ? NULL : code->m;
+
+#if defined(ENABLE_INTRP)
+ }
+#endif
+ }
+#if PRINTMETHODS
+ else {
+ printf("ra=%p sp=%p, ", ra, sp);
+ 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
+ printf("ra=%p sp=%p, ", ra, sp);
+ method_print(m);
+ printf(": JIT");
+ fflush(stdout);
#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_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1);
- stacktrace_fillInStackTrace_method(&buffer, m, pv,
- ((u1 *) ra) - 1);
+ /* get the current stack frame size */
- /* get the current stack frame size */
+ framesize = *((u4 *) (pv + FrameSize));
- framesize = *((u4 *) (pv + FrameSize));
+#if PRINTMETHODS
+ printf(", framesize=%d\n", framesize);
+ fflush(stdout);
+#endif
- /* get return address of current stack frame */
+ /* get return address of current stack frame */
+#if defined(ENABLE_JIT)
+# if defined(ENABLE_INTRP)
+ if (opt_intrp)
+ ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
+ else
+# endif
ra = md_stacktrace_get_returnaddress(sp, framesize);
+#else
+ ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
+#endif
- /* 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));
+#if defined(ENABLE_INTRP)
+ if (opt_intrp)
+ pv = codegen_get_pv_from_pc(ra);
+ else
+#endif
+ {
+#if defined(ENABLE_JIT)
+# 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
+ }
- /* walk the stack */
+ code = *((codeinfo **) (pv + CodeinfoPointer));
-#if defined(__I386__) || defined (__X86_64__)
- sp += framesize + SIZEOF_VOID_P;
+ /* For asm_vm_call_method the codeinfo pointer is NULL. */
+
+ m = (code == NULL) ? NULL : code->m;
+
+ /* walk the stack */
+
+#if defined(ENABLE_INTRP)
+ if (opt_intrp)
+ sp = *(u1 **) (sp - framesize);
+ else
+#endif
+ {
+#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;
+ sp += framesize;
#endif
- }
+ }
}
-
- if (coll)
- coll(target,&buffer);
-
- if (buffer.needsFree)
- free(buffer.start);
-
- return;
}
- *target = NULL;
+ /* return the stacktracebuffer */
+
+ return stb;
}
-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));
+/* stacktrace_fillInStackTrace *************************************************
- dest->needsFree=0;
- dest->size=dest->full;
- dest->start=(stacktraceelement*)(dest+1);
+ Generate a stacktrace from the current thread for
+ java.lang.VMThrowable.fillInStackTrace.
- /*
- 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");
- */
-}
+*******************************************************************************/
+
+stacktracecontainer *stacktrace_fillInStackTrace(void)
+{
+ stacktracebuffer *stb;
+ stacktracecontainer *gcstc;
+ s4 gcstc_size;
+ s4 dumpsize;
+ CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
+
+ /* mark start of dump memory area */
+
+ dumpsize = dump_size();
+
+ /* create a stacktrace from the current thread */
+
+ stb = stacktrace_create(THREADOBJECT);
+ if (!stb)
+ 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 */
-void cacao_stacktrace_NormalTrace(void **target) {
- cacao_stacktrace_fillInStackTrace(target,&stackTraceCollector);
+ gcstc_size = sizeof(stacktracebuffer) +
+ sizeof(stacktrace_entry) * stb->used;
+ gcstc = (stacktracecontainer *) builtin_newarray_byte(gcstc_size);
+
+ if (gcstc == NULL)
+ goto return_NULL;
+
+ gcstc->stb.capacity = stb->capacity;
+ gcstc->stb.used = stb->used;
+ gcstc->stb.entries = gcstc->data;
+
+ MCOPY(gcstc->data, stb->entries, stacktrace_entry, stb->used);
+
+ /* release dump memory */
+
+ dump_release(dumpsize);
+
+ CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
+ stacktrace_overhead)
+ return gcstc;
+
+return_NULL:
+ dump_release(dumpsize);
+
+ CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
+ stacktrace_overhead)
+
+ return NULL;
}
+/* stacktrace_getClassContext **************************************************
+
+ Creates a Class context array.
+
+ RETURN VALUE:
+ the array of java.lang.Class objects, or
+ NULL if an exception has been thrown
+
+*******************************************************************************/
-static void classContextCollector(void **target, stackTraceBuffer *buffer)
+java_objectarray *stacktrace_getClassContext(void)
{
- java_objectarray *tmpArray;
- stacktraceelement *current;
- stacktraceelement *start;
- size_t size;
- size_t targetSize;
- s4 i;
-
- size = buffer->full;
- targetSize = 0;
-
- for (i = 0; i < size; i++)
- if (buffer->start[i].method != 0)
- targetSize++;
-
- start = buffer->start;
- start++;
- targetSize--;
-
- if (targetSize > 0) {
- if (start->method && (start->method->class == class_java_lang_SecurityManager)) {
- targetSize--;
- start++;
- }
- }
+ stacktracebuffer *stb;
+ stacktrace_entry *ste;
+ java_objectarray *oa;
+ s4 oalength;
+ s4 i;
+ s4 dumpsize;
+ CYCLES_STATS_DECLARE_AND_START
+
+ /* mark start of dump memory area */
+
+ dumpsize = dump_size();
+
+ /* create a stacktrace for the current thread */
+
+ stb = stacktrace_create(THREADOBJECT);
+ if (!stb)
+ goto return_NULL;
+
+ /* calculate the size of the Class array */
+
+ for (i = 0, oalength = 0; i < stb->used; i++)
+ if (stb->entries[i].method != NULL)
+ oalength++;
+
+ /* The first entry corresponds to the method whose implementation */
+ /* calls stacktrace_getClassContext. We remove that entry. */
+
+ ste = &(stb->entries[0]);
+ ste++;
+ oalength--;
+
+ /* allocate the Class array */
- tmpArray = builtin_anewarray(targetSize, class_java_lang_Class);
+ oa = builtin_anewarray(oalength, class_java_lang_Class);
+ if (!oa)
+ goto return_NULL;
- for(i = 0, current = start; i < targetSize; i++, current++) {
- /* XXX TWISTI: should we use this skipping for native stubs? */
+ /* fill the Class array from the stacktracebuffer */
- if (!current->method) {
+ for(i = 0; i < oalength; i++, ste++) {
+ if (ste->method == NULL) {
i--;
continue;
}
- use_class_as_object(current->method->class);
-
- tmpArray->data[i] = (java_objectheader *) current->method->class;
+ oa->data[i] = (java_objectheader *) ste->method->class;
}
- *target = tmpArray;
-}
+ /* release dump memory */
+
+ dump_release(dumpsize);
+ CYCLES_STATS_END(stacktrace_getClassContext)
+ return oa;
-java_objectarray *cacao_createClassContextArray() {
- java_objectarray *array=0;
- cacao_stacktrace_fillInStackTrace((void**)&array,&classContextCollector);
- return array;
-
+return_NULL:
+ dump_release(dumpsize);
+
+ CYCLES_STATS_END(stacktrace_getClassContext)
+
+ return NULL;
}
-/* stacktrace_classLoaderCollector *********************************************
+/* stacktrace_getCurrentClass **************************************************
+
+ Find the current class by walking the stack trace.
- XXX
+ Quote from the JNI documentation:
+
+ In the Java 2 Platform, FindClass locates the class loader
+ associated with the current native method. If the native code
+ belongs to a system class, no class loader will be
+ involved. Otherwise, the proper class loader will be invoked to
+ load and link the named class. When FindClass is called through the
+ Invocation Interface, there is no current native method or its
+ associated class loader. In that case, the result of
+ ClassLoader.getBaseClassLoader is used."
*******************************************************************************/
-static void stacktrace_classLoaderCollector(void **target,
- stackTraceBuffer *buffer)
+#if defined(ENABLE_JAVASE)
+classinfo *stacktrace_getCurrentClass(void)
{
- stacktraceelement *current;
- stacktraceelement *start;
+ stacktracebuffer *stb;
+ stacktrace_entry *ste;
methodinfo *m;
- ptrint size;
s4 i;
+ s4 dumpsize;
+ CYCLES_STATS_DECLARE_AND_START
- size = buffer->full;
- start = &(buffer->start[0]);
+ /* mark start of dump memory area */
- for(i = 0, current = start; i < size; i++, current++) {
- m = current->method;
+ dumpsize = dump_size();
- if (!m)
+ /* create a stacktrace for the current thread */
+
+ stb = stacktrace_create(THREADOBJECT);
+ if (!stb)
+ goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
+
+ /* iterate over all stacktrace entries and find the first suitable
+ class */
+
+ for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
+ m = ste->method;
+
+ if (m == NULL)
continue;
- if (m->class == class_java_security_PrivilegedAction) {
- *target = NULL;
- return;
- }
+ if (m->class == class_java_security_PrivilegedAction)
+ goto return_NULL;
+
+ if (m->class != NULL) {
+ dump_release(dumpsize);
- if (m->class->classloader) {
- *target = (java_lang_ClassLoader *) m->class->classloader;
- return;
+ CYCLES_STATS_END(stacktrace_getCurrentClass)
+
+ return m->class;
}
}
- *target = NULL;
+ /* no Java method found on the stack */
+
+return_NULL:
+ dump_release(dumpsize);
+
+ CYCLES_STATS_END(stacktrace_getCurrentClass)
+
+ return NULL;
}
+#endif /* ENABLE_JAVASE */
+
+/* stacktrace_getStack *********************************************************
-/* cacao_currentClassLoader ****************************************************
+ Create a 2-dimensional array for java.security.VMAccessControler.
- XXX
+ RETURN VALUE:
+ the arrary, or
+ NULL if an exception has been thrown
*******************************************************************************/
-java_objectheader *cacao_currentClassLoader(void)
+#if defined(ENABLE_JAVASE)
+java_objectarray *stacktrace_getStack(void)
{
- java_objectheader *header=0;
+ 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
- cacao_stacktrace_fillInStackTrace((void**)&header,
- &stacktrace_classLoaderCollector);
+ /* mark start of dump memory area */
- return header;
-}
+ dumpsize = dump_size();
+ /* create a stacktrace for the current thread */
-static
-void callingMethodCollector(void **target, stackTraceBuffer *buffer) {
- if (buffer->full >2) (*target)=buffer->start[2].method;
- else (*target=0);
-}
+ stb = stacktrace_create(THREADOBJECT);
-methodinfo *cacao_callingMethod() {
- methodinfo *method;
- cacao_stacktrace_fillInStackTrace((void**)&method,&callingMethodCollector);
- return method;
-}
+ if (stb == NULL)
+ goto return_NULL;
+ /* get the first stacktrace entry */
-static
-void getStackCollector(void **target, stackTraceBuffer *buffer)
-{
- java_objectarray *classes;
- java_objectarray *methodnames;
- java_objectarray **result=(java_objectarray**)target;
- java_lang_String *str;
- classinfo *c;
- stacktraceelement *current;
- int i,size;
+ ste = &(stb->entries[0]);
- /*log_text("getStackCollector");*/
+ /* allocate all required arrays */
- size = buffer->full;
+ oa = builtin_anewarray(2, arrayclass_java_lang_Object);
- *result = builtin_anewarray(2, arrayclass_java_lang_Object);
+ if (oa == NULL)
+ goto return_NULL;
- if (!(*result))
- return;
+ classes = builtin_anewarray(stb->used, class_java_lang_Class);
- classes = builtin_anewarray(size, class_java_lang_Class);
+ if (classes == NULL)
+ goto return_NULL;
- if (!classes)
- return;
+ methodnames = builtin_anewarray(stb->used, class_java_lang_String);
- methodnames = builtin_anewarray(size, class_java_lang_String);
+ if (methodnames == NULL)
+ goto return_NULL;
- if (!methodnames)
- return;
+ /* set up the 2-dimensional array */
+
+ oa->data[0] = (java_objectheader *) classes;
+ oa->data[1] = (java_objectheader *) methodnames;
+
+ /* iterate over all stacktrace entries */
- (*result)->data[0] = (java_objectheader *) classes;
- (*result)->data[1] = (java_objectheader *) methodnames;
+ for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
+ c = ste->method->class;
- /*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;
- methodnames->data[i] = (java_objectheader *) str;
- /*printf("getStackCollector: %s.%s\n",c->name->text,current->method->name->text);*/
+
+ string = javastring_new(ste->method->name);
+
+ if (string == NULL)
+ goto return_NULL;
+
+ methodnames->data[i] = string;
}
- /*if (*exceptionptr) panic("Exception in getStackCollector");*/
+ /* return the 2-dimensional array */
- /*log_text("loop left");*/
- return;
+ dump_release(dumpsize);
+ CYCLES_STATS_END(stacktrace_getStack)
+
+ return oa;
+
+return_NULL:
+ dump_release(dumpsize);
+
+ CYCLES_STATS_END(stacktrace_getStack)
+
+ return NULL;
}
+#endif /* ENABLE_JAVASE */
+
+
+/* stacktrace_print_trace_from_buffer ******************************************
+ 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.
-java_objectarray *cacao_getStackForVMAccessController()
+*******************************************************************************/
+
+void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
{
- java_objectarray *result=0;
- cacao_stacktrace_fillInStackTrace((void**)&result,&getStackCollector);
- return result;
+ stacktrace_entry *ste;
+ methodinfo *m;
+ s4 i;
+
+ ste = &(stb->entries[0]);
+
+ for (i = 0; i < stb->used; i++, ste++) {
+ m = ste->method;
+
+ printf("\tat ");
+ utf_display_printable_ascii_classname(m->class->name);
+ printf(".");
+ utf_display_printable_ascii(m->name);
+ utf_display_printable_ascii(m->descriptor);
+
+ if (m->flags & ACC_NATIVE) {
+ puts("(Native Method)");
+
+ } else {
+ printf("(");
+ utf_display_printable_ascii(m->class->sourcefile);
+ printf(":%d)\n", (u4) ste->linenumber);
+ }
+ }
+
+ /* just to be sure */
+
+ fflush(stdout);
}
*******************************************************************************/
-void stacktrace_dump_trace(void)
+void stacktrace_dump_trace(threadobject *thread)
{
- stackTraceBuffer *buffer;
- stacktraceelement *element;
- methodinfo *m;
- s4 i;
+ stacktracebuffer *stb;
+ s4 dumpsize;
-#if 0
- /* get thread stackframeinfo */
+ /* mark start of dump memory area */
- info = &THREADINFO->_stackframeinfo;
+ dumpsize = dump_size();
- /* fill stackframeinfo structure */
+ /* create a stacktrace for the current thread */
- tmp.oldThreadspecificHeadValue = *info;
- tmp.addressOfThreadspecificHead = info;
- tmp.method = NULL;
- tmp.beginOfJavaStackframe = NULL;
- tmp.returnToFromNative = _mc->gregs[REG_RIP];
+ stb = stacktrace_create(thread);
- *info = &tmp;
-#endif
+ /* print stacktrace */
- /* generate stacktrace */
+ if (stb != NULL)
+ stacktrace_print_trace_from_buffer(stb);
+ else {
+ puts("\t<<No stacktrace available>>");
+ fflush(stdout);
+ }
- cacao_stacktrace_NormalTrace((void **) &buffer);
+ dump_release(dumpsize);
+}
- /* print stacktrace */
- if (buffer) {
- element = buffer->start;
+/* stacktrace_print_trace ******************************************************
- for (i = 0; i < buffer->size; i++, element++) {
- m = element->method;
+ Print the stacktrace of a given exception. More or less a wrapper
+ to stacktrace_print_trace_from_buffer.
- 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");
+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;
- } else {
- printf("(");
- utf_display(m->class->sourcefile);
- printf(":%d)\n", (u4) element->linenumber);
- }
- }
- }
+ t = (java_lang_Throwable *) xptr;
+
+ if (t == NULL)
+ return;
- /* flush stdout */
+ /* now print the stacktrace */
- fflush(stdout);
+#if defined(WITH_CLASSPATH_GNU)
+ vmt = t->vmState;
+ 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);
+}
+
+
+#if defined(ENABLE_CYCLES_STATS)
+void stacktrace_print_cycles_stats(FILE *file)
+{
+ CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
+ CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
+ CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
+ CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
+ CYCLES_STATS_PRINT(stacktrace_getStack ,file);
}
+#endif
/*
* c-basic-offset: 4
* tab-width: 4
* End:
+ * vim:noexpandtab:sw=4:ts=4:
*/