1 /* src/vm/jit/stacktrace.c - machine independet 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
29 Changes: Christian Thalinger
32 $Id: stacktrace.c 4921 2006-05-15 14:24:36Z twisti $
46 #include "mm/memory.h"
47 #include "native/native.h"
49 #include "vm/global.h" /* required here for native includes */
50 #include "native/include/java_lang_ClassLoader.h"
51 #include "native/include/java_lang_Throwable.h"
52 #include "native/include/java_lang_VMThrowable.h"
54 #if defined(ENABLE_THREADS)
55 # include "threads/native/threads.h"
57 # include "threads/none/threads.h"
60 #include "toolbox/logging.h"
61 #include "vm/builtin.h"
63 #include "vm/exceptions.h"
64 #include "vm/loader.h"
65 #include "vm/options.h"
66 #include "vm/stringlocal.h"
68 #include "vm/jit/asmpart.h"
69 #include "vm/jit/codegen-common.h"
70 #include "vm/jit/methodheader.h"
71 #include "vm/cycles-stats.h"
74 /* linenumbertable_entry ******************************************************/
76 /* Keep the type of line the same as the pointer type, otherwise we
77 run into alignment troubles (like on MIPS64). */
79 typedef struct linenumbertable_entry linenumbertable_entry;
81 struct linenumbertable_entry {
82 ptrint line; /* NOTE: see doc/inlining_stacktrace.txt for */
83 u1 *pc; /* special meanings of line and pc. */
86 /* global variables ***********************************************************/
88 #if !defined(ENABLE_THREADS)
89 stackframeinfo *_no_threads_stackframeinfo = NULL;
92 CYCLES_STATS_DECLARE(stacktrace_overhead ,100,1)
93 CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace,40,5000)
94 CYCLES_STATS_DECLARE(stacktrace_getClassContext ,40,5000)
95 CYCLES_STATS_DECLARE(stacktrace_getCurrentClass ,40,5000)
96 CYCLES_STATS_DECLARE(stacktrace_getStack ,40,10000)
99 /* stacktrace_create_stackframeinfo ********************************************
101 Creates an stackframe info structure for inline code in the
104 *******************************************************************************/
106 #if defined(ENABLE_INTRP)
107 void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv, u1 *sp,
110 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_findmethod(ra);
126 #if defined(ENABLE_JIT)
127 pv = md_codegen_findmethod(ra);
132 /* get methodinfo pointer from data segment */
134 m = *((methodinfo **) (pv + MethodPointer));
136 /* fill new stackframe info structure */
144 /* xpc is the same as ra, but is required in stacktrace_create */
148 /* store new stackframe info pointer */
152 #endif /* defined(ENABLE_INTRP) */
155 /* stacktrace_create_inline_stackframeinfo *************************************
157 Creates an stackframe info structure for an inline exception stub.
159 *******************************************************************************/
161 void stacktrace_create_inline_stackframeinfo(stackframeinfo *sfi, u1 *pv,
162 u1 *sp, u1 *ra, u1 *xpc)
164 stackframeinfo **psfi;
166 /* get current stackframe info pointer */
168 psfi = STACKFRAMEINFO;
170 #if defined(ENABLE_INTRP)
172 /* if we don't have pv handy */
175 pv = codegen_findmethod(ra);
180 /* fill new stackframe info structure */
189 /* store new stackframe info pointer */
195 /* stacktrace_create_extern_stackframeinfo *************************************
197 Creates an stackframe info structure for an extern exception
198 (hardware or assembler).
200 *******************************************************************************/
202 void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
203 u1 *sp, u1 *ra, u1 *xpc)
205 stackframeinfo **psfi;
206 #if !defined(__I386__) && !defined(__X86_64__)
209 #if defined(ENABLE_JIT)
213 /* get current stackframe info pointer */
215 psfi = STACKFRAMEINFO;
217 /* sometimes we don't have pv handy (e.g. in asmpart.S:
218 L_asm_call_jit_compiler_exception or in the interpreter). */
221 #if defined(ENABLE_INTRP)
223 pv = codegen_findmethod(ra);
227 #if defined(ENABLE_JIT)
228 pv = md_codegen_findmethod(ra);
233 #if defined(ENABLE_JIT)
234 # if defined(ENABLE_INTRP)
235 /* When using the interpreter, we pass RA to the function. */
239 # if defined(__I386__) || defined(__X86_64__)
240 /* On i386 and x86_64 we always have to get the return address
243 framesize = *((u4 *) (pv + FrameSize));
245 ra = md_stacktrace_get_returnaddress(sp, framesize);
247 /* If the method is a non-leaf function, we need to get the return
248 address from the stack. For leaf functions the return address
249 is set correctly. This makes the assembler and the signal
250 handler code simpler. */
252 isleafmethod = *((s4 *) (pv + IsLeaf));
255 framesize = *((u4 *) (pv + FrameSize));
257 ra = md_stacktrace_get_returnaddress(sp, framesize);
260 # if defined(ENABLE_INTRP)
263 #endif /* defined(ENABLE_JIT) */
265 /* fill new stackframe info structure */
274 /* store new stackframe info pointer */
280 /* stacktrace_create_native_stackframeinfo *************************************
282 Creates a stackframe info structure for a native stub.
284 *******************************************************************************/
286 void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv,
289 stackframeinfo **psfi;
292 /* get methodinfo pointer from data segment */
294 m = *((methodinfo **) (pv + MethodPointer));
296 /* get current stackframe info pointer */
298 psfi = STACKFRAMEINFO;
300 /* fill new stackframe info structure */
309 /* store new stackframe info pointer */
315 /* stacktrace_remove_stackframeinfo ********************************************
319 *******************************************************************************/
321 void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
323 stackframeinfo **psfi;
325 /* get current stackframe info pointer */
327 psfi = STACKFRAMEINFO;
329 /* restore the old pointer */
335 /* stacktrace_inline_arithmeticexception ***************************************
337 Creates an ArithemticException for inline stub.
339 *******************************************************************************/
341 java_objectheader *stacktrace_inline_arithmeticexception(u1 *pv, u1 *sp,
345 java_objectheader *o;
347 /* create stackframeinfo */
349 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
351 /* create exception */
353 o = new_arithmeticexception();
355 /* remove stackframeinfo */
357 stacktrace_remove_stackframeinfo(&sfi);
363 /* stacktrace_inline_arrayindexoutofboundsexception ****************************
365 Creates an ArrayIndexOutOfBoundsException for inline stub.
367 *******************************************************************************/
369 java_objectheader *stacktrace_inline_arrayindexoutofboundsexception(u1 *pv,
376 java_objectheader *o;
378 /* create stackframeinfo */
380 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
382 /* create exception */
384 o = new_arrayindexoutofboundsexception(index);
386 /* remove stackframeinfo */
388 stacktrace_remove_stackframeinfo(&sfi);
394 /* stacktrace_inline_arraystoreexception ***************************************
396 Creates an ArrayStoreException for inline stub.
398 *******************************************************************************/
400 java_objectheader *stacktrace_inline_arraystoreexception(u1 *pv, u1 *sp, u1 *ra,
404 java_objectheader *o;
406 /* create stackframeinfo */
408 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
410 /* create exception */
412 o = new_arraystoreexception();
414 /* remove stackframeinfo */
416 stacktrace_remove_stackframeinfo(&sfi);
422 /* stacktrace_inline_classcastexception ****************************************
424 Creates an ClassCastException for inline stub.
426 *******************************************************************************/
428 java_objectheader *stacktrace_inline_classcastexception(u1 *pv, u1 *sp, u1 *ra,
432 java_objectheader *o;
434 /* create stackframeinfo */
436 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
438 /* create exception */
440 o = new_classcastexception();
442 /* remove stackframeinfo */
444 stacktrace_remove_stackframeinfo(&sfi);
450 /* stacktrace_inline_nullpointerexception **************************************
452 Creates an NullPointerException for inline stub.
454 *******************************************************************************/
456 java_objectheader *stacktrace_inline_nullpointerexception(u1 *pv, u1 *sp,
460 java_objectheader *o;
462 /* create stackframeinfo */
464 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
466 /* create exception */
468 o = new_nullpointerexception();
470 /* remove stackframeinfo */
472 stacktrace_remove_stackframeinfo(&sfi);
478 /* stacktrace_inline_fillInStackTrace ******************************************
480 Fills in the correct stacktrace into an existing exception object
481 (this one is for inline exception stubs).
483 *******************************************************************************/
485 java_objectheader *stacktrace_inline_fillInStackTrace(u1 *pv, u1 *sp, u1 *ra,
489 java_objectheader *o;
492 /* create stackframeinfo */
494 stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
501 /* clear exception */
503 *exceptionptr = NULL;
505 /* resolve methodinfo pointer from exception object */
507 m = class_resolvemethod(o->vftbl->class,
508 utf_fillInStackTrace,
509 utf_void__java_lang_Throwable);
513 (void) vm_call_method(m, o);
515 /* remove stackframeinfo */
517 stacktrace_remove_stackframeinfo(&sfi);
523 /* stacktrace_hardware_arithmeticexception *************************************
525 Creates an ArithemticException for inline stub.
527 *******************************************************************************/
529 java_objectheader *stacktrace_hardware_arithmeticexception(u1 *pv, u1 *sp,
533 java_objectheader *o;
535 /* create stackframeinfo */
537 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
539 /* create exception */
541 o = new_arithmeticexception();
543 /* remove stackframeinfo */
545 stacktrace_remove_stackframeinfo(&sfi);
551 /* stacktrace_hardware_nullpointerexception ************************************
553 Creates an NullPointerException for the SIGSEGV signal handler.
555 *******************************************************************************/
557 java_objectheader *stacktrace_hardware_nullpointerexception(u1 *pv, u1 *sp,
561 java_objectheader *o;
563 /* create stackframeinfo */
565 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
567 /* create exception */
569 o = new_nullpointerexception();
571 /* remove stackframeinfo */
573 stacktrace_remove_stackframeinfo(&sfi);
579 /* stacktrace_add_entry ********************************************************
581 Adds a new entry to the stacktrace buffer.
583 *******************************************************************************/
585 static void stacktrace_add_entry(stacktracebuffer *stb, methodinfo *m, u2 line)
587 stacktrace_entry *ste;
589 /* check if we already reached the buffer capacity */
591 if (stb->used >= stb->capacity) {
592 /* reallocate new memory */
594 stb->entries = DMREALLOC(stb->entries, stacktrace_entry, stb->capacity,
595 stb->capacity + STACKTRACE_CAPACITY_INCREMENT);
597 /* set new buffer capacity */
599 stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
602 /* insert the current entry */
604 ste = &(stb->entries[stb->used]);
607 ste->linenumber = line;
609 /* increase entries used count */
615 /* stacktrace_add_method_intern ************************************************
617 This function is used by stacktrace_add_method to search the line number
618 table for the line corresponding to a given pc. The function recurses for
621 *******************************************************************************/
623 static bool stacktrace_add_method_intern(stacktracebuffer *stb,
625 linenumbertable_entry *lntentry,
629 linenumbertable_entry *lntinline; /* special entry for inlined method */
634 /* Find the line number for the specified PC (going backwards
635 in the linenumber table). The linenumber table size is zero
638 for (; lntsize > 0; lntsize--, lntentry--) {
640 /* did we reach the current line? */
642 /* Note: In case of inlining this may actually compare the pc
643 against a methodinfo *, yielding a non-sensical
644 result. This is no problem, however, as we ignore such
645 entries in the switch below. This way we optimize for the
646 common case (ie. a real pc in lntentry->pc). */
648 if (pc >= lntentry->pc) {
650 /* check for special inline entries (see
651 doc/inlining_stacktrace.txt for details */
653 if ((s4)lntentry->line < 0) {
654 switch (lntentry->line) {
656 /* begin of inlined method (ie. INLINE_END
659 lntinline = --lntentry;/* get entry with methodinfo * */
660 lntentry--; /* skip the special entry */
663 /* search inside the inlined method */
664 if (stacktrace_add_method_intern(
666 (methodinfo*) lntinline->pc,
671 /* the inlined method contained the pc */
672 assert(lntinline->line <= -3);
673 stacktrace_add_entry(stb, m, (-3) - lntinline->line);
676 /* pc was not in inlined method, continue
677 search. Entries inside the inlined method
678 will be skipped because their lntentry->pc
679 is higher than pc. */
683 /* end of inlined method */
686 /* default: is only reached for an -3-line entry
687 after a skipped -2 entry. We can safely ignore
688 it and continue searching. */
692 /* found a normal entry */
693 stacktrace_add_entry(stb, m, lntentry->line);
703 /* stacktrace_add_method *******************************************************
705 Add stacktrace entries[1] for the given method to the stacktrace buffer.
708 stb.........stacktracebuffer to fill
709 m...........method for which entries should be created
710 pv..........pv of method
711 pc..........position of program counter within the method's code
714 true, if stacktrace entries were successfully created, false otherwise.
716 [1] In case of inlined methods there may be more than one stacktrace
717 entry for a codegen-level method. (see doc/inlining_stacktrace.txt)
719 *******************************************************************************/
721 static bool stacktrace_add_method(stacktracebuffer *stb, methodinfo *m, u1 *pv,
724 ptrint lntsize; /* size of line number table */
725 u1 *lntstart; /* start of line number table */
726 linenumbertable_entry *lntentry; /* points to last entry in the table */
727 codeinfo *code; /* compiled realization of method */
729 /* get size of line number table */
731 lntsize = *((ptrint *) (pv + LineNumberTableSize));
732 lntstart = *((u1 **) (pv + LineNumberTableStart));
734 /* Subtract the size of the line number entry of the structure,
735 since the line number table start points to the pc. */
737 lntentry = (linenumbertable_entry *) (lntstart - SIZEOF_VOID_P);
739 /* find the realization of the method the pc is in */
740 /* XXX Note: This is preliminary. It would be cleaner */
741 /* to get the codeinfo * from the PV */
748 dolog("Could not find codeinfo for Current PC: %p",(void*)pc);
753 if (((ptrint)pc >= (ptrint)code->entrypoint)
755 ( (pc - (u1*)code->entrypoint) < code->mcodelength ))
764 /* search the line number table */
766 if (stacktrace_add_method_intern(stb, m, lntentry, lntsize, pc))
769 /* If we get here, just add the entry with line number 0. */
771 stacktrace_add_entry(stb, m, 0);
777 /* stacktrace_create ***********************************************************
779 Generates a stacktrace from the thread passed into a
780 stacktracebuffer. The stacktracebuffer is allocated on the GC
784 pointer to the stacktracebuffer, or
785 NULL if an exception has been thrown
787 *******************************************************************************/
789 stacktracebuffer *stacktrace_create(threadobject* thread)
791 stacktracebuffer *stb;
800 /* prevent compiler warnings */
806 /* create a stacktracebuffer in dump memory */
808 stb = DNEW(stacktracebuffer);
810 stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
812 stb->entries = DMNEW(stacktrace_entry, STACKTRACE_CAPACITY_DEFAULT);
814 /* The first element in the stackframe chain must always be a
815 native stackframeinfo (VMThrowable.fillInStackTrace is a native
818 /* We don't use the STACKFRAMEINFO macro here, as we have to use
819 the passed thread. */
821 #if defined(ENABLE_THREADS)
822 sfi = thread->_stackframeinfo;
824 sfi = _no_threads_stackframeinfo;
827 #define PRINTMETHODS 0
830 printf("\n\nfillInStackTrace start:\n");
834 /* Loop while we have a method pointer (asm_calljavafunction has
835 NULL) or there is a stackframeinfo in the chain. */
840 /* m == NULL should only happen for the first time and inline
841 stackframe infos, like from the exception stubs or the
845 /* for native stub stackframe infos, pv is always NULL */
847 if (sfi->pv == NULL) {
848 /* get methodinfo, sp and ra from the current stackframe info */
851 sp = sfi->sp; /* sp of parent Java function */
855 stacktrace_add_entry(stb, m, 0);
858 printf("ra=%p sp=%p, ", ra, sp);
860 printf(": native stub\n");
863 /* This is an native stub stackframe info, so we can
864 get the parent pv from the return address
867 #if defined(ENABLE_INTRP)
869 pv = codegen_findmethod(ra);
873 #if defined(ENABLE_JIT)
874 pv = md_codegen_findmethod(ra);
878 /* get methodinfo pointer from parent data segment */
880 m = *((methodinfo **) (pv + MethodPointer));
883 /* Inline stackframe infos are special: they have a
884 xpc of the actual exception position and the return
885 address saved since an inline stackframe info can
886 also be in a leaf method (no return address saved
887 on stack!!!). ATTENTION: This one is also for
888 hardware exceptions!!! */
890 /* get methodinfo, sp and ra from the current stackframe info */
892 m = sfi->method; /* m == NULL */
893 pv = sfi->pv; /* pv of parent Java function */
894 sp = sfi->sp; /* sp of parent Java function */
895 ra = sfi->ra; /* ra of parent Java function */
896 xpc = sfi->xpc; /* actual exception position */
899 printf("ra=%p sp=%p, ", ra, sp);
900 printf("NULL: inline stub\n");
904 /* get methodinfo from current Java method */
906 m = *((methodinfo **) (pv + MethodPointer));
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 parent */
947 #if defined(ENABLE_JIT)
948 pv = md_codegen_findmethod(ra);
951 m = *((methodinfo **) (pv + MethodPointer));
953 #if defined(ENABLE_INTRP)
959 printf("ra=%p sp=%p, ", ra, sp);
960 printf("asm_calljavafunction\n");
966 /* get previous stackframeinfo in the chain */
972 printf("ra=%p sp=%p, ", ra, sp);
978 /* JIT method found, add it to the stacktrace (we subtract
979 1 from the return address since it points the the
980 instruction after call). */
982 stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1);
984 /* get the current stack frame size */
986 framesize = *((u4 *) (pv + FrameSize));
989 printf(", framesize=%d\n", framesize);
993 /* get return address of current stack frame */
995 #if defined(ENABLE_JIT)
996 # if defined(ENABLE_INTRP)
998 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
1001 ra = md_stacktrace_get_returnaddress(sp, framesize);
1003 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
1006 /* get data segment and methodinfo pointer from parent method */
1008 #if defined(ENABLE_INTRP)
1010 pv = codegen_findmethod(ra);
1014 #if defined(ENABLE_JIT)
1015 pv = md_codegen_findmethod(ra);
1019 m = *((methodinfo **) (pv + MethodPointer));
1021 /* walk the stack */
1023 #if defined(ENABLE_INTRP)
1025 sp = *(u1 **) (sp - framesize);
1029 #if defined(__I386__) || defined (__X86_64__)
1030 sp += framesize + SIZEOF_VOID_P;
1038 /* return the stacktracebuffer */
1044 /* stacktrace_fillInStackTrace *************************************************
1046 Generate a stacktrace from the current thread for
1047 java.lang.VMThrowable.fillInStackTrace.
1049 *******************************************************************************/
1051 stacktracebuffer *stacktrace_fillInStackTrace(void)
1053 stacktracebuffer *stb;
1054 stacktracebuffer *gcstb;
1056 CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
1058 /* mark start of dump memory area */
1060 dumpsize = dump_size();
1062 /* create a stacktrace from the current thread */
1064 stb = stacktrace_create(THREADOBJECT);
1068 /* allocate memory from the GC heap and copy the stacktrace buffer */
1070 gcstb = GCNEW(stacktracebuffer);
1075 gcstb->capacity = stb->capacity;
1076 gcstb->used = stb->used;
1077 gcstb->entries = GCMNEW(stacktrace_entry, stb->used);
1079 if (gcstb->entries == NULL)
1082 MCOPY(gcstb->entries, stb->entries, stacktrace_entry, stb->used);
1084 /* release dump memory */
1086 dump_release(dumpsize);
1088 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
1089 stacktrace_overhead)
1093 dump_release(dumpsize);
1095 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
1096 stacktrace_overhead)
1102 /* stacktrace_getClassContext **************************************************
1104 Creates a Class context array.
1107 the array of java.lang.Class objects, or
1108 NULL if an exception has been thrown
1110 *******************************************************************************/
1112 java_objectarray *stacktrace_getClassContext(void)
1114 stacktracebuffer *stb;
1115 stacktrace_entry *ste;
1116 java_objectarray *oa;
1120 CYCLES_STATS_DECLARE_AND_START
1122 /* mark start of dump memory area */
1124 dumpsize = dump_size();
1126 /* create a stacktrace for the current thread */
1128 stb = stacktrace_create(THREADOBJECT);
1132 /* calculate the size of the Class array */
1134 for (i = 0, oalength = 0; i < stb->used; i++)
1135 if (stb->entries[i].method != NULL)
1138 /* The first entry corresponds to the method whose implementation */
1139 /* calls stacktrace_getClassContext. We remove that entry. */
1141 ste = &(stb->entries[0]);
1145 /* allocate the Class array */
1147 oa = builtin_anewarray(oalength, class_java_lang_Class);
1151 /* fill the Class array from the stacktracebuffer */
1153 for(i = 0; i < oalength; i++, ste++) {
1154 if (ste->method == NULL) {
1159 oa->data[i] = (java_objectheader *) ste->method->class;
1162 /* release dump memory */
1164 dump_release(dumpsize);
1166 CYCLES_STATS_END(stacktrace_getClassContext)
1171 dump_release(dumpsize);
1173 CYCLES_STATS_END(stacktrace_getClassContext)
1179 /* stacktrace_getCurrentClass **************************************************
1181 Find the current class by walking the stack trace.
1183 Quote from the JNI documentation:
1185 In the Java 2 Platform, FindClass locates the class loader
1186 associated with the current native method. If the native code
1187 belongs to a system class, no class loader will be
1188 involved. Otherwise, the proper class loader will be invoked to
1189 load and link the named class. When FindClass is called through the
1190 Invocation Interface, there is no current native method or its
1191 associated class loader. In that case, the result of
1192 ClassLoader.getBaseClassLoader is used."
1194 *******************************************************************************/
1196 classinfo *stacktrace_getCurrentClass(void)
1198 stacktracebuffer *stb;
1199 stacktrace_entry *ste;
1203 CYCLES_STATS_DECLARE_AND_START
1205 /* mark start of dump memory area */
1207 dumpsize = dump_size();
1209 /* create a stacktrace for the current thread */
1211 stb = stacktrace_create(THREADOBJECT);
1213 goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
1215 /* iterate over all stacktrace entries and find the first suitable
1218 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
1224 if (m->class == class_java_security_PrivilegedAction)
1227 if (m->class != NULL) {
1228 dump_release(dumpsize);
1230 CYCLES_STATS_END(stacktrace_getCurrentClass)
1236 /* no Java method found on the stack */
1239 dump_release(dumpsize);
1241 CYCLES_STATS_END(stacktrace_getCurrentClass)
1247 /* stacktrace_getStack *********************************************************
1249 Create a 2-dimensional array for java.security.VMAccessControler.
1253 NULL if an exception has been thrown
1255 *******************************************************************************/
1257 java_objectarray *stacktrace_getStack(void)
1259 stacktracebuffer *stb;
1260 stacktrace_entry *ste;
1261 java_objectarray *oa;
1262 java_objectarray *classes;
1263 java_objectarray *methodnames;
1265 java_lang_String *str;
1268 CYCLES_STATS_DECLARE_AND_START
1270 /* mark start of dump memory area */
1272 dumpsize = dump_size();
1274 /* create a stacktrace for the current thread */
1276 stb = stacktrace_create(THREADOBJECT);
1280 /* get the first stacktrace entry */
1282 ste = &(stb->entries[0]);
1284 /* allocate all required arrays */
1286 oa = builtin_anewarray(2, arrayclass_java_lang_Object);
1291 classes = builtin_anewarray(stb->used, class_java_lang_Class);
1296 methodnames = builtin_anewarray(stb->used, class_java_lang_String);
1301 /* set up the 2-dimensional array */
1303 oa->data[0] = (java_objectheader *) classes;
1304 oa->data[1] = (java_objectheader *) methodnames;
1306 /* iterate over all stacktrace entries */
1308 for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
1309 c = ste->method->class;
1311 classes->data[i] = (java_objectheader *) c;
1312 str = javastring_new(ste->method->name);
1317 methodnames->data[i] = (java_objectheader *) str;
1320 /* return the 2-dimensional array */
1322 dump_release(dumpsize);
1324 CYCLES_STATS_END(stacktrace_getStack)
1329 dump_release(dumpsize);
1331 CYCLES_STATS_END(stacktrace_getStack)
1337 /* stacktrace_print_trace_from_buffer ******************************************
1339 Print the stacktrace of a given stacktracebuffer with CACAO intern
1340 methods (no Java help). This method is used by
1341 stacktrace_dump_trace and builtin_trace_exception.
1343 *******************************************************************************/
1345 static void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
1347 stacktrace_entry *ste;
1351 ste = &(stb->entries[0]);
1353 for (i = 0; i < stb->used; i++, ste++) {
1357 utf_display_printable_ascii_classname(m->class->name);
1359 utf_display_printable_ascii(m->name);
1360 utf_display_printable_ascii(m->descriptor);
1362 if (m->flags & ACC_NATIVE) {
1363 puts("(Native Method)");
1367 utf_display_printable_ascii(m->class->sourcefile);
1368 printf(":%d)\n", (u4) ste->linenumber);
1372 /* just to be sure */
1378 /* stacktrace_dump_trace *******************************************************
1380 This method is call from signal_handler_sigusr1 to dump the
1381 stacktrace of the current thread to stdout.
1383 *******************************************************************************/
1385 void stacktrace_dump_trace(void)
1387 stacktracebuffer *stb;
1391 /* get methodinfo pointer from data segment */
1393 m = *((methodinfo **) (pv + MethodPointer));
1395 /* get current stackframe info pointer */
1397 psfi = STACKFRAMEINFO;
1399 /* fill new stackframe info structure */
1407 /* store new stackframe info pointer */
1412 /* mark start of dump memory area */
1414 dumpsize = dump_size();
1416 /* create a stacktrace for the current thread */
1418 stb = stacktrace_create(THREADOBJECT);
1420 /* print stacktrace */
1423 stacktrace_print_trace_from_buffer(stb);
1426 puts("\t<<No stacktrace available>>");
1430 dump_release(dumpsize);
1434 /* stacktrace_print_trace ******************************************************
1436 Print the stacktrace of a given exception. More or less a wrapper
1437 to stacktrace_print_trace_from_buffer.
1439 *******************************************************************************/
1441 void stacktrace_print_trace(java_objectheader *xptr)
1443 java_lang_Throwable *t;
1444 java_lang_VMThrowable *vmt;
1445 stacktracebuffer *stb;
1447 t = (java_lang_Throwable *) xptr;
1452 /* now print the stacktrace */
1455 stb = (stacktracebuffer *) vmt->vmData;
1457 stacktrace_print_trace_from_buffer(stb);
1461 #if defined(ENABLE_CYCLES_STATS)
1462 void stacktrace_print_cycles_stats(FILE *file)
1464 CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
1465 CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
1466 CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
1467 CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
1468 CYCLES_STATS_PRINT(stacktrace_getStack ,file);
1474 * These are local overrides for various environment variables in Emacs.
1475 * Please do not remove this and leave it at the end of the file, where
1476 * Emacs will automagically detect them.
1477 * ---------------------------------------------------------------------
1480 * indent-tabs-mode: t
1484 * vim:noexpandtab:sw=4:ts=4: