1 /* src/vm/jit/stacktrace.c - machine independent stacktrace system
3 Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 Contact: cacao@cacaojvm.org
27 Authors: Joseph Wenninger
31 $Id: stacktrace.c 5941 2006-11-09 10:23:04Z twisti $
44 #include "mm/gc-common.h"
45 #include "mm/memory.h"
46 #include "native/native.h"
48 #include "vm/global.h" /* required here for native includes */
49 #include "native/include/java_lang_ClassLoader.h"
50 #include "native/include/java_lang_Throwable.h"
51 #include "native/include/java_lang_VMThrowable.h"
53 #if defined(ENABLE_THREADS)
54 # include "threads/native/threads.h"
56 # include "threads/none/threads.h"
59 #include "toolbox/logging.h"
60 #include "vm/builtin.h"
62 #include "vm/exceptions.h"
63 #include "vm/loader.h"
64 #include "vm/options.h"
65 #include "vm/stringlocal.h"
67 #include "vm/jit/asmpart.h"
68 #include "vm/jit/codegen-common.h"
69 #include "vm/jit/methodheader.h"
70 #include "vm/cycles-stats.h"
73 /* linenumbertable_entry ******************************************************/
75 /* Keep the type of line the same as the pointer type, otherwise we
76 run into alignment troubles (like on MIPS64). */
78 typedef struct linenumbertable_entry linenumbertable_entry;
80 struct linenumbertable_entry {
81 ptrint line; /* NOTE: see doc/inlining_stacktrace.txt for */
82 u1 *pc; /* special meanings of line and pc. */
85 /* global variables ***********************************************************/
87 #if !defined(ENABLE_THREADS)
88 stackframeinfo *_no_threads_stackframeinfo = NULL;
91 CYCLES_STATS_DECLARE(stacktrace_overhead ,100,1)
92 CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace,40,5000)
93 CYCLES_STATS_DECLARE(stacktrace_getClassContext ,40,5000)
94 CYCLES_STATS_DECLARE(stacktrace_getCurrentClass ,40,5000)
95 CYCLES_STATS_DECLARE(stacktrace_getStack ,40,10000)
98 /* stacktrace_create_stackframeinfo ********************************************
100 Creates an stackframe info structure for inline code in the
103 *******************************************************************************/
105 #if defined(ENABLE_INTRP)
106 void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv, u1 *sp,
109 stackframeinfo **psfi;
113 /* get current stackframe info pointer */
115 psfi = STACKFRAMEINFO;
117 /* if we don't have pv handy */
120 #if defined(ENABLE_INTRP)
122 pv = codegen_get_pv_from_pc(ra);
126 #if defined(ENABLE_JIT)
127 pv = md_codegen_get_pv_from_pc(ra);
132 /* get codeinfo pointer from data segment */
134 code = *((codeinfo **) (pv + CodeinfoPointer));
136 /* For asm_vm_call_method the codeinfo pointer is NULL. */
138 m = (code == NULL) ? NULL : code->m;
140 /* fill new stackframe info structure */
148 /* xpc is the same as ra, but is required in stacktrace_create */
152 /* store new stackframe info pointer */
156 #endif /* defined(ENABLE_INTRP) */
159 /* stacktrace_create_inline_stackframeinfo *************************************
161 Creates an stackframe info structure for an inline exception stub.
163 *******************************************************************************/
165 void stacktrace_create_inline_stackframeinfo(stackframeinfo *sfi, u1 *pv,
166 u1 *sp, u1 *ra, u1 *xpc)
168 stackframeinfo **psfi;
170 /* get current stackframe info pointer */
172 psfi = STACKFRAMEINFO;
174 #if defined(ENABLE_INTRP)
176 /* if we don't have pv handy */
179 pv = codegen_get_pv_from_pc(ra);
184 /* fill new stackframe info structure */
193 /* store new stackframe info pointer */
199 /* stacktrace_create_extern_stackframeinfo *************************************
201 Creates an stackframe info structure for an extern exception
202 (hardware or assembler).
204 *******************************************************************************/
206 void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
207 u1 *sp, u1 *ra, u1 *xpc)
209 stackframeinfo **psfi;
210 #if !defined(__I386__) && !defined(__X86_64__)
213 #if defined(ENABLE_JIT)
217 /* get current stackframe info pointer */
219 psfi = STACKFRAMEINFO;
221 /* sometimes we don't have pv handy (e.g. in asmpart.S:
222 L_asm_call_jit_compiler_exception or in the interpreter). */
225 #if defined(ENABLE_INTRP)
227 pv = codegen_get_pv_from_pc(ra);
231 #if defined(ENABLE_JIT)
232 pv = md_codegen_get_pv_from_pc(ra);
237 #if defined(ENABLE_JIT)
238 # if defined(ENABLE_INTRP)
239 /* When using the interpreter, we pass RA to the function. */
243 # if defined(__I386__) || defined(__X86_64__)
244 /* On i386 and x86_64 we always have to get the return address
247 framesize = *((u4 *) (pv + FrameSize));
249 ra = md_stacktrace_get_returnaddress(sp, framesize);
251 /* If the method is a non-leaf function, we need to get the return
252 address from the stack. For leaf functions the return address
253 is set correctly. This makes the assembler and the signal
254 handler code simpler. */
256 isleafmethod = *((s4 *) (pv + IsLeaf));
259 framesize = *((u4 *) (pv + FrameSize));
261 ra = md_stacktrace_get_returnaddress(sp, framesize);
264 # if defined(ENABLE_INTRP)
267 #endif /* defined(ENABLE_JIT) */
269 /* fill new stackframe info structure */
278 /* store new stackframe info pointer */
284 /* stacktrace_create_native_stackframeinfo *************************************
286 Creates a stackframe info structure for a native stub.
288 *******************************************************************************/
290 void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv,
293 stackframeinfo **psfi;
297 /* get codeinfo pointer from data segment */
299 code = *((codeinfo **) (pv + CodeinfoPointer));
301 /* For asm_vm_call_method the codeinfo pointer is NULL. */
303 m = (code == NULL) ? NULL : code->m;
305 /* get current stackframe info pointer */
307 psfi = STACKFRAMEINFO;
309 /* fill new stackframe info structure */
318 /* store new stackframe info pointer */
324 /* stacktrace_remove_stackframeinfo ********************************************
326 Remove the topmost stackframeinfo in the current thread.
328 *******************************************************************************/
330 void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
332 stackframeinfo **psfi;
334 /* get current stackframe info pointer */
336 psfi = STACKFRAMEINFO;
338 /* restore the old pointer */
344 /* stacktrace_inline_arithmeticexception ***************************************
346 Creates an ArithemticException for inline stub.
348 *******************************************************************************/
350 java_objectheader *stacktrace_inline_arithmeticexception(u1 *pv, u1 *sp,
354 java_objectheader *o;
356 /* create stackframeinfo */
358 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
360 /* create exception */
362 o = new_arithmeticexception();
364 /* remove stackframeinfo */
366 stacktrace_remove_stackframeinfo(&sfi);
372 /* stacktrace_inline_arrayindexoutofboundsexception ****************************
374 Creates an ArrayIndexOutOfBoundsException for inline stub.
376 *******************************************************************************/
378 java_objectheader *stacktrace_inline_arrayindexoutofboundsexception(u1 *pv,
385 java_objectheader *o;
387 /* create stackframeinfo */
389 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
391 /* create exception */
393 o = new_arrayindexoutofboundsexception(index);
395 /* remove stackframeinfo */
397 stacktrace_remove_stackframeinfo(&sfi);
403 /* stacktrace_inline_arraystoreexception ***************************************
405 Creates an ArrayStoreException for inline stub.
407 *******************************************************************************/
409 java_objectheader *stacktrace_inline_arraystoreexception(u1 *pv, u1 *sp, u1 *ra,
413 java_objectheader *o;
415 /* create stackframeinfo */
417 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
419 /* create exception */
421 o = exceptions_new_arraystoreexception();
423 /* remove stackframeinfo */
425 stacktrace_remove_stackframeinfo(&sfi);
431 /* stacktrace_inline_classcastexception ****************************************
433 Creates an ClassCastException for inline stub.
435 *******************************************************************************/
437 java_objectheader *stacktrace_inline_classcastexception(u1 *pv, u1 *sp, u1 *ra,
439 java_objectheader *o)
442 java_objectheader *e;
444 /* create stackframeinfo */
446 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
448 /* create exception */
450 e = exceptions_new_classcastexception(o);
452 /* remove stackframeinfo */
454 stacktrace_remove_stackframeinfo(&sfi);
460 /* stacktrace_inline_nullpointerexception **************************************
462 Creates an NullPointerException for inline stub.
464 *******************************************************************************/
466 java_objectheader *stacktrace_inline_nullpointerexception(u1 *pv, u1 *sp,
470 java_objectheader *o;
472 /* create stackframeinfo */
474 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
476 /* create exception */
478 o = exceptions_new_nullpointerexception();
480 /* remove stackframeinfo */
482 stacktrace_remove_stackframeinfo(&sfi);
488 /* stacktrace_inline_fillInStackTrace ******************************************
490 Fills in the correct stacktrace into an existing exception object
491 (this one is for inline exception stubs).
493 *******************************************************************************/
495 java_objectheader *stacktrace_inline_fillInStackTrace(u1 *pv, u1 *sp, u1 *ra,
499 java_objectheader *o;
502 /* create stackframeinfo */
504 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
511 /* clear exception */
513 *exceptionptr = NULL;
515 /* resolve methodinfo pointer from exception object */
517 m = class_resolvemethod(o->vftbl->class,
518 utf_fillInStackTrace,
519 utf_void__java_lang_Throwable);
523 (void) vm_call_method(m, o);
525 /* remove stackframeinfo */
527 stacktrace_remove_stackframeinfo(&sfi);
533 /* stacktrace_hardware_arithmeticexception *************************************
535 Creates an ArithemticException for inline stub.
537 *******************************************************************************/
539 java_objectheader *stacktrace_hardware_arithmeticexception(u1 *pv, u1 *sp,
543 java_objectheader *o;
545 /* create stackframeinfo */
547 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
549 /* create exception */
551 o = new_arithmeticexception();
553 /* remove stackframeinfo */
555 stacktrace_remove_stackframeinfo(&sfi);
561 /* stacktrace_hardware_nullpointerexception ************************************
563 Creates an NullPointerException for the SIGSEGV signal handler.
565 *******************************************************************************/
567 java_objectheader *stacktrace_hardware_nullpointerexception(u1 *pv, u1 *sp,
571 java_objectheader *o;
573 /* create stackframeinfo */
575 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
577 /* create exception */
579 o = exceptions_new_nullpointerexception();
581 /* remove stackframeinfo */
583 stacktrace_remove_stackframeinfo(&sfi);
589 /* stacktrace_add_entry ********************************************************
591 Adds a new entry to the stacktrace buffer.
593 *******************************************************************************/
595 static void stacktrace_add_entry(stacktracebuffer *stb, methodinfo *m, u2 line)
597 stacktrace_entry *ste;
599 /* check if we already reached the buffer capacity */
601 if (stb->used >= stb->capacity) {
602 /* reallocate new memory */
604 stb->entries = DMREALLOC(stb->entries, stacktrace_entry, stb->capacity,
605 stb->capacity + STACKTRACE_CAPACITY_INCREMENT);
607 /* set new buffer capacity */
609 stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
612 /* insert the current entry */
614 ste = &(stb->entries[stb->used]);
617 ste->linenumber = line;
619 /* increase entries used count */
625 /* stacktrace_add_method_intern ************************************************
627 This function is used by stacktrace_add_method to search the line number
628 table for the line corresponding to a given pc. The function recurses for
631 *******************************************************************************/
633 static bool stacktrace_add_method_intern(stacktracebuffer *stb,
635 linenumbertable_entry *lntentry,
639 linenumbertable_entry *lntinline; /* special entry for inlined method */
644 /* Find the line number for the specified PC (going backwards
645 in the linenumber table). The linenumber table size is zero
648 for (; lntsize > 0; lntsize--, lntentry--) {
650 /* did we reach the current line? */
652 /* Note: In case of inlining this may actually compare the pc
653 against a methodinfo *, yielding a non-sensical
654 result. This is no problem, however, as we ignore such
655 entries in the switch below. This way we optimize for the
656 common case (ie. a real pc in lntentry->pc). */
658 if (pc >= lntentry->pc) {
660 /* check for special inline entries (see
661 doc/inlining_stacktrace.txt for details */
663 if ((s4)lntentry->line < 0) {
664 switch (lntentry->line) {
666 /* begin of inlined method (ie. INLINE_END
669 lntinline = --lntentry;/* get entry with methodinfo * */
670 lntentry--; /* skip the special entry */
673 /* search inside the inlined method */
674 if (stacktrace_add_method_intern(
676 (methodinfo*) lntinline->pc,
681 /* the inlined method contained the pc */
682 assert(lntinline->line <= -3);
683 stacktrace_add_entry(stb, m, (-3) - lntinline->line);
686 /* pc was not in inlined method, continue
687 search. Entries inside the inlined method
688 will be skipped because their lntentry->pc
689 is higher than pc. */
693 /* end of inlined method */
696 /* default: is only reached for an -3-line entry
697 after a skipped -2 entry. We can safely ignore
698 it and continue searching. */
702 /* found a normal entry */
703 stacktrace_add_entry(stb, m, lntentry->line);
713 /* stacktrace_add_method *******************************************************
715 Add stacktrace entries[1] for the given method to the stacktrace buffer.
718 stb.........stacktracebuffer to fill
719 m...........method for which entries should be created
720 pv..........pv of method
721 pc..........position of program counter within the method's code
724 true, if stacktrace entries were successfully created, false otherwise.
726 [1] In case of inlined methods there may be more than one stacktrace
727 entry for a codegen-level method. (see doc/inlining_stacktrace.txt)
729 *******************************************************************************/
731 static bool stacktrace_add_method(stacktracebuffer *stb, methodinfo *m, u1 *pv,
734 ptrint lntsize; /* size of line number table */
735 u1 *lntstart; /* start of line number table */
736 linenumbertable_entry *lntentry; /* points to last entry in the table */
737 codeinfo *code; /* compiled realization of method */
739 /* get size of line number table */
741 lntsize = *((ptrint *) (pv + LineNumberTableSize));
742 lntstart = *((u1 **) (pv + LineNumberTableStart));
744 /* Subtract the size of the line number entry of the structure,
745 since the line number table start points to the pc. */
747 lntentry = (linenumbertable_entry *) (lntstart - SIZEOF_VOID_P);
749 /* find the realization of the method the pc is in */
751 code = *((codeinfo **) (pv + CodeinfoPointer));
753 /* search the line number table */
755 if (stacktrace_add_method_intern(stb, m, lntentry, lntsize, pc))
758 /* If we get here, just add the entry with line number 0. */
760 stacktrace_add_entry(stb, m, 0);
766 /* stacktrace_create ***********************************************************
768 Generates a stacktrace from the thread passed into a
769 stacktracebuffer. The stacktracebuffer is allocated on the GC
773 pointer to the stacktracebuffer, or
774 NULL if an exception has been thrown
776 *******************************************************************************/
778 stacktracebuffer *stacktrace_create(threadobject* thread)
780 stacktracebuffer *stb;
790 /* prevent compiler warnings */
796 /* create a stacktracebuffer in dump memory */
798 stb = DNEW(stacktracebuffer);
800 stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
802 stb->entries = DMNEW(stacktrace_entry, STACKTRACE_CAPACITY_DEFAULT);
804 /* The first element in the stackframe chain must always be a
805 native stackframeinfo (VMThrowable.fillInStackTrace is a native
808 /* We don't use the STACKFRAMEINFO macro here, as we have to use
809 the passed thread. */
811 #if defined(ENABLE_THREADS)
812 sfi = thread->_stackframeinfo;
814 sfi = _no_threads_stackframeinfo;
817 #define PRINTMETHODS 0
820 printf("\n\nfillInStackTrace start:\n");
824 /* Loop while we have a method pointer (asm_calljavafunction has
825 NULL) or there is a stackframeinfo in the chain. */
829 while ((m != NULL) || (sfi != NULL)) {
830 /* m == NULL should only happen for the first time and inline
831 stackframe infos, like from the exception stubs or the
835 /* for native stub stackframe infos, pv is always NULL */
837 if (sfi->pv == NULL) {
838 /* get methodinfo, sp and ra from the current stackframe info */
841 sp = sfi->sp; /* sp of parent Java function */
845 stacktrace_add_entry(stb, m, 0);
848 printf("ra=%p sp=%p, ", ra, sp);
850 printf(": native stub\n");
853 /* This is an native stub stackframe info, so we can
854 get the parent pv from the return address
857 #if defined(ENABLE_INTRP)
859 pv = codegen_get_pv_from_pc(ra);
863 #if defined(ENABLE_JIT)
864 pv = md_codegen_get_pv_from_pc(ra);
868 /* get methodinfo pointer from parent data segment */
870 code = *((codeinfo **) (pv + CodeinfoPointer));
872 /* For asm_vm_call_method the codeinfo pointer is
875 m = (code == NULL) ? NULL : code->m;
878 /* Inline stackframe infos are special: they have a
879 xpc of the actual exception position and the return
880 address saved since an inline stackframe info can
881 also be in a leaf method (no return address saved
882 on stack!!!). ATTENTION: This one is also for
883 hardware exceptions!!! */
885 /* get methodinfo, sp and ra from the current stackframe info */
887 m = sfi->method; /* m == NULL */
888 pv = sfi->pv; /* pv of parent Java function */
889 sp = sfi->sp; /* sp of parent Java function */
890 ra = sfi->ra; /* ra of parent Java function */
891 xpc = sfi->xpc; /* actual exception position */
894 printf("ra=%p sp=%p, ", ra, sp);
895 printf("NULL: inline stub\n");
899 /* get methodinfo from current Java method */
901 code = *((codeinfo **) (pv + CodeinfoPointer));
903 /* For asm_vm_call_method the codeinfo pointer is
906 m = (code == NULL) ? NULL : code->m;
908 /* if m == NULL, this is a asm_calljavafunction call */
912 printf("ra=%p sp=%p, ", ra, sp);
914 printf(": inline stub parent");
918 #if defined(ENABLE_INTRP)
922 /* add the method to the stacktrace */
924 stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) xpc));
926 /* get the current stack frame size */
928 framesize = *((u4 *) (pv + FrameSize));
931 printf(", framesize=%d\n", framesize);
935 /* Set stack pointer to stackframe of parent Java
936 function of the current Java function. */
938 #if defined(__I386__) || defined (__X86_64__)
939 sp += framesize + SIZEOF_VOID_P;
944 /* get data segment and methodinfo pointer from
947 #if defined(ENABLE_JIT)
948 pv = md_codegen_get_pv_from_pc(ra);
951 code = *((codeinfo **) (pv + CodeinfoPointer));
953 /* For asm_vm_call_method the codeinfo pointer is
956 m = (code == NULL) ? NULL : code->m;
958 #if defined(ENABLE_INTRP)
964 printf("ra=%p sp=%p, ", ra, sp);
965 printf("asm_calljavafunction\n");
971 /* get previous stackframeinfo in the chain */
977 printf("ra=%p sp=%p, ", ra, sp);
983 /* JIT method found, add it to the stacktrace (we subtract
984 1 from the return address since it points the the
985 instruction after call). */
987 stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1);
989 /* get the current stack frame size */
991 framesize = *((u4 *) (pv + FrameSize));
994 printf(", framesize=%d\n", framesize);
998 /* get return address of current stack frame */
1000 #if defined(ENABLE_JIT)
1001 # if defined(ENABLE_INTRP)
1003 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
1006 ra = md_stacktrace_get_returnaddress(sp, framesize);
1008 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
1011 /* get data segment and methodinfo pointer from parent method */
1013 #if defined(ENABLE_INTRP)
1015 pv = codegen_get_pv_from_pc(ra);
1019 #if defined(ENABLE_JIT)
1020 pv = md_codegen_get_pv_from_pc(ra);
1024 code = *((codeinfo **) (pv + CodeinfoPointer));
1026 /* For asm_vm_call_method the codeinfo pointer is NULL. */
1028 m = (code == NULL) ? NULL : code->m;
1030 /* walk the stack */
1032 #if defined(ENABLE_INTRP)
1034 sp = *(u1 **) (sp - framesize);
1038 #if defined(__I386__) || defined (__X86_64__)
1039 sp += framesize + SIZEOF_VOID_P;
1047 /* return the stacktracebuffer */
1053 /* stacktrace_fillInStackTrace *************************************************
1055 Generate a stacktrace from the current thread for
1056 java.lang.VMThrowable.fillInStackTrace.
1058 *******************************************************************************/
1060 stacktracecontainer *stacktrace_fillInStackTrace(void)
1062 stacktracebuffer *stb;
1063 stacktracecontainer *gcstc;
1066 CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
1068 /* mark start of dump memory area */
1070 dumpsize = dump_size();
1072 /* create a stacktrace from the current thread */
1074 stb = stacktrace_create(THREADOBJECT);
1078 /* allocate memory from the GC heap and copy the stacktrace buffer */
1079 /* ATTENTION: use stacktracecontainer for this and make it look like
1082 gcstc_size = sizeof(stacktracebuffer) +
1083 sizeof(stacktrace_entry) * stb->used;
1084 gcstc = (stacktracecontainer *) builtin_newarray_byte(gcstc_size);
1089 gcstc->stb.capacity = stb->capacity;
1090 gcstc->stb.used = stb->used;
1091 gcstc->stb.entries = gcstc->data;
1093 MCOPY(gcstc->data, stb->entries, stacktrace_entry, stb->used);
1095 /* release dump memory */
1097 dump_release(dumpsize);
1099 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
1100 stacktrace_overhead)
1104 dump_release(dumpsize);
1106 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
1107 stacktrace_overhead)
1113 /* stacktrace_getClassContext **************************************************
1115 Creates a Class context array.
1118 the array of java.lang.Class objects, or
1119 NULL if an exception has been thrown
1121 *******************************************************************************/
1123 java_objectarray *stacktrace_getClassContext(void)
1125 stacktracebuffer *stb;
1126 stacktrace_entry *ste;
1127 java_objectarray *oa;
1131 CYCLES_STATS_DECLARE_AND_START
1133 /* mark start of dump memory area */
1135 dumpsize = dump_size();
1137 /* create a stacktrace for the current thread */
1139 stb = stacktrace_create(THREADOBJECT);
1143 /* calculate the size of the Class array */
1145 for (i = 0, oalength = 0; i < stb->used; i++)
1146 if (stb->entries[i].method != NULL)
1149 /* The first entry corresponds to the method whose implementation */
1150 /* calls stacktrace_getClassContext. We remove that entry. */
1152 ste = &(stb->entries[0]);
1156 /* allocate the Class array */
1158 oa = builtin_anewarray(oalength, class_java_lang_Class);
1162 /* fill the Class array from the stacktracebuffer */
1164 for(i = 0; i < oalength; i++, ste++) {
1165 if (ste->method == NULL) {
1170 oa->data[i] = (java_objectheader *) ste->method->class;
1173 /* release dump memory */
1175 dump_release(dumpsize);
1177 CYCLES_STATS_END(stacktrace_getClassContext)
1182 dump_release(dumpsize);
1184 CYCLES_STATS_END(stacktrace_getClassContext)
1190 /* stacktrace_getCurrentClass **************************************************
1192 Find the current class by walking the stack trace.
1194 Quote from the JNI documentation:
1196 In the Java 2 Platform, FindClass locates the class loader
1197 associated with the current native method. If the native code
1198 belongs to a system class, no class loader will be
1199 involved. Otherwise, the proper class loader will be invoked to
1200 load and link the named class. When FindClass is called through the
1201 Invocation Interface, there is no current native method or its
1202 associated class loader. In that case, the result of
1203 ClassLoader.getBaseClassLoader is used."
1205 *******************************************************************************/
1207 classinfo *stacktrace_getCurrentClass(void)
1209 stacktracebuffer *stb;
1210 stacktrace_entry *ste;
1214 CYCLES_STATS_DECLARE_AND_START
1216 /* mark start of dump memory area */
1218 dumpsize = dump_size();
1220 /* create a stacktrace for the current thread */
1222 stb = stacktrace_create(THREADOBJECT);
1224 goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
1226 /* iterate over all stacktrace entries and find the first suitable
1229 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
1235 if (m->class == class_java_security_PrivilegedAction)
1238 if (m->class != NULL) {
1239 dump_release(dumpsize);
1241 CYCLES_STATS_END(stacktrace_getCurrentClass)
1247 /* no Java method found on the stack */
1250 dump_release(dumpsize);
1252 CYCLES_STATS_END(stacktrace_getCurrentClass)
1258 /* stacktrace_getStack *********************************************************
1260 Create a 2-dimensional array for java.security.VMAccessControler.
1264 NULL if an exception has been thrown
1266 *******************************************************************************/
1268 java_objectarray *stacktrace_getStack(void)
1270 stacktracebuffer *stb;
1271 stacktrace_entry *ste;
1272 java_objectarray *oa;
1273 java_objectarray *classes;
1274 java_objectarray *methodnames;
1276 java_lang_String *str;
1279 CYCLES_STATS_DECLARE_AND_START
1281 /* mark start of dump memory area */
1283 dumpsize = dump_size();
1285 /* create a stacktrace for the current thread */
1287 stb = stacktrace_create(THREADOBJECT);
1291 /* get the first stacktrace entry */
1293 ste = &(stb->entries[0]);
1295 /* allocate all required arrays */
1297 oa = builtin_anewarray(2, arrayclass_java_lang_Object);
1302 classes = builtin_anewarray(stb->used, class_java_lang_Class);
1307 methodnames = builtin_anewarray(stb->used, class_java_lang_String);
1312 /* set up the 2-dimensional array */
1314 oa->data[0] = (java_objectheader *) classes;
1315 oa->data[1] = (java_objectheader *) methodnames;
1317 /* iterate over all stacktrace entries */
1319 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
1320 c = ste->method->class;
1322 classes->data[i] = (java_objectheader *) c;
1323 str = javastring_new(ste->method->name);
1328 methodnames->data[i] = (java_objectheader *) str;
1331 /* return the 2-dimensional array */
1333 dump_release(dumpsize);
1335 CYCLES_STATS_END(stacktrace_getStack)
1340 dump_release(dumpsize);
1342 CYCLES_STATS_END(stacktrace_getStack)
1348 /* stacktrace_print_trace_from_buffer ******************************************
1350 Print the stacktrace of a given stacktracebuffer with CACAO intern
1351 methods (no Java help). This method is used by
1352 stacktrace_dump_trace and builtin_trace_exception.
1354 *******************************************************************************/
1356 static void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
1358 stacktrace_entry *ste;
1362 ste = &(stb->entries[0]);
1364 for (i = 0; i < stb->used; i++, ste++) {
1368 utf_display_printable_ascii_classname(m->class->name);
1370 utf_display_printable_ascii(m->name);
1371 utf_display_printable_ascii(m->descriptor);
1373 if (m->flags & ACC_NATIVE) {
1374 puts("(Native Method)");
1378 utf_display_printable_ascii(m->class->sourcefile);
1379 printf(":%d)\n", (u4) ste->linenumber);
1383 /* just to be sure */
1389 /* stacktrace_dump_trace *******************************************************
1391 This method is call from signal_handler_sigusr1 to dump the
1392 stacktrace of the current thread to stdout.
1394 *******************************************************************************/
1396 void stacktrace_dump_trace(threadobject *thread)
1398 stacktracebuffer *stb;
1402 /* get methodinfo pointer from data segment */
1404 m = *((methodinfo **) (pv + MethodPointer));
1406 /* get current stackframe info pointer */
1408 psfi = STACKFRAMEINFO;
1410 /* fill new stackframe info structure */
1418 /* store new stackframe info pointer */
1423 /* mark start of dump memory area */
1425 dumpsize = dump_size();
1427 /* create a stacktrace for the current thread */
1429 stb = stacktrace_create(thread);
1431 /* print stacktrace */
1434 stacktrace_print_trace_from_buffer(stb);
1436 puts("\t<<No stacktrace available>>");
1440 dump_release(dumpsize);
1444 /* stacktrace_print_trace ******************************************************
1446 Print the stacktrace of a given exception. More or less a wrapper
1447 to stacktrace_print_trace_from_buffer.
1449 *******************************************************************************/
1451 void stacktrace_print_trace(java_objectheader *xptr)
1453 java_lang_Throwable *t;
1454 java_lang_VMThrowable *vmt;
1455 stacktracecontainer *stc;
1456 stacktracebuffer *stb;
1458 t = (java_lang_Throwable *) xptr;
1463 /* now print the stacktrace */
1466 stc = (stacktracecontainer *) vmt->vmData;
1469 stacktrace_print_trace_from_buffer(stb);
1473 #if defined(ENABLE_CYCLES_STATS)
1474 void stacktrace_print_cycles_stats(FILE *file)
1476 CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
1477 CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
1478 CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
1479 CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
1480 CYCLES_STATS_PRINT(stacktrace_getStack ,file);
1486 * These are local overrides for various environment variables in Emacs.
1487 * Please do not remove this and leave it at the end of the file, where
1488 * Emacs will automagically detect them.
1489 * ---------------------------------------------------------------------
1492 * indent-tabs-mode: t
1496 * vim:noexpandtab:sw=4:ts=4: