1 /* src/vm/jit/stacktrace.c - machine independent stacktrace system
3 Copyright (C) 1996-2005, 2006, 2007, 2008
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 This file is part of CACAO.
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2, or (at
11 your option) any later version.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
37 #include "mm/gc-common.h"
38 #include "mm/memory.h"
40 #include "vm/jit/stacktrace.h"
42 #include "vm/global.h" /* required here for native includes */
43 #include "native/jni.h"
44 #include "native/llni.h"
46 #include "native/include/java_lang_Object.h"
47 #include "native/include/java_lang_Throwable.h"
49 #if defined(WITH_CLASSPATH_GNU)
50 # include "native/include/gnu_classpath_Pointer.h"
51 # 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"
63 #include "vm/builtin.h"
64 #include "vm/cycles-stats.h"
65 #include "vm/exceptions.h"
66 #include "vm/stringlocal.h"
69 #include "vm/jit/asmpart.h"
70 #include "vm/jit/codegen-common.h"
71 #include "vm/jit/linenumbertable.h"
72 #include "vm/jit/methodheader.h"
74 #include "vmcore/class.h"
75 #include "vmcore/loader.h"
76 #include "vmcore/options.h"
79 /* global variables ***********************************************************/
80 #if !defined(ENABLE_THREADS)
81 stackframeinfo_t *_no_threads_stackframeinfo = NULL;
84 CYCLES_STATS_DECLARE(stacktrace_overhead , 100, 1)
85 CYCLES_STATS_DECLARE(stacktrace_get, 40, 5000)
86 CYCLES_STATS_DECLARE(stacktrace_getClassContext , 40, 5000)
87 CYCLES_STATS_DECLARE(stacktrace_getCurrentClass , 40, 5000)
88 CYCLES_STATS_DECLARE(stacktrace_get_stack , 40, 10000)
91 /* stacktrace_stackframeinfo_add ***********************************************
93 Fills a stackframe info structure with the given or calculated
94 values and adds it to the chain.
96 *******************************************************************************/
98 void stacktrace_stackframeinfo_add(stackframeinfo_t *sfi, u1 *pv, u1 *sp, u1 *ra, u1 *xpc)
100 stackframeinfo_t **psfi;
102 #if defined(ENABLE_JIT)
106 /* get current stackframe info pointer */
108 psfi = &STACKFRAMEINFO;
110 /* sometimes we don't have pv handy (e.g. in asmpart.S:
111 L_asm_call_jit_compiler_exception or in the interpreter). */
114 #if defined(ENABLE_INTRP)
116 pv = codegen_get_pv_from_pc(ra);
120 #if defined(ENABLE_JIT)
121 # if defined(__SPARC_64__)
122 pv = md_get_pv_from_stackframe(sp);
124 pv = md_codegen_get_pv_from_pc(ra);
130 /* Get codeinfo pointer for the parent Java method. */
132 code = code_get_codeinfo_for_pv(pv);
135 /* assert(m != NULL); */
137 #if defined(ENABLE_JIT)
138 # if defined(ENABLE_INTRP)
139 /* When using the interpreter, we pass RA to the function. */
143 # if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__M68K__)
144 /* On i386 and x86_64 we always have to get the return address
146 /* m68k has return address on stack always */
147 /* On S390 we use REG_RA as REG_ITMP3, so we have always to get
148 the RA from stack. */
150 framesize = *((u4 *) (pv + FrameSize));
152 ra = md_stacktrace_get_returnaddress(sp, framesize);
154 /* If the method is a non-leaf function, we need to get the
155 return address from the stack. For leaf functions the
156 return address is set correctly. This makes the assembler
157 and the signal handler code simpler. The code is NULL is
158 the asm_vm_call_method special case. */
160 if ((code == NULL) || !code_is_leafmethod(code)) {
161 framesize = *((u4 *) (pv + FrameSize));
163 ra = md_stacktrace_get_returnaddress(sp, framesize);
166 # if defined(ENABLE_INTRP)
171 /* Calculate XPC when not given. The XPC is then the return
172 address of the current method minus 1 because the RA points to
173 the instruction after the call instruction. This is required
174 e.g. for method stubs. */
177 xpc = (void *) (((intptr_t) ra) - 1);
180 /* Fill new stackframeinfo structure. */
190 if (opt_DebugStackFrameInfo) {
192 log_print("[stackframeinfo add : sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
193 sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
194 method_print(sfi->code->m);
200 /* Store new stackframeinfo pointer. */
204 /* set the native world flag for the current thread */
205 /* ATTENTION: This flag tells the GC how to treat this thread in case of
206 a collection. Set this flag _after_ a valid stackframe info was set. */
208 THREAD_NATIVEWORLD_ENTER;
212 /* stacktrace_stackframeinfo_remove ********************************************
214 Remove the given stackframeinfo from the chain in the current
217 *******************************************************************************/
219 void stacktrace_stackframeinfo_remove(stackframeinfo_t *sfi)
221 stackframeinfo_t **psfi;
223 /* clear the native world flag for the current thread */
224 /* ATTENTION: Clear this flag _before_ removing the stackframe info */
226 THREAD_NATIVEWORLD_EXIT;
228 /* get current stackframe info pointer */
230 psfi = &STACKFRAMEINFO;
233 if (opt_DebugStackFrameInfo) {
235 log_print("[stackframeinfo remove: sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
236 sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
237 method_print(sfi->code->m);
243 /* restore the old pointer */
249 /* stacktrace_stackframeinfo_fill **********************************************
251 Fill the temporary stackframeinfo structure with the values given
255 tmpsfi ... temporary stackframeinfo
256 sfi ...... stackframeinfo to be used in the next iteration
258 *******************************************************************************/
260 static inline void stacktrace_stackframeinfo_fill(stackframeinfo_t *tmpsfi, stackframeinfo_t *sfi)
264 assert(tmpsfi != NULL);
267 /* Fill the temporary stackframeinfo. */
269 tmpsfi->code = sfi->code;
270 tmpsfi->pv = sfi->pv;
271 tmpsfi->sp = sfi->sp;
272 tmpsfi->ra = sfi->ra;
273 tmpsfi->xpc = sfi->xpc;
275 /* Set the previous stackframe info of the temporary one to the
276 next in the chain. */
278 tmpsfi->prev = sfi->prev;
281 /* Print current method information. */
283 if (opt_DebugStackTrace) {
284 log_println("[stacktrace start]");
286 log_print("[stacktrace: method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
287 tmpsfi->code->m, tmpsfi->pv, tmpsfi->sp, tmpsfi->ra,
289 method_print(tmpsfi->code->m);
297 /* stacktrace_stackframeinfo_next **********************************************
299 Walk the stack (or the stackframeinfo-chain) to the next method and
300 return the new stackframe values in the temporary stackframeinfo
303 ATTENTION: This function does NOT skip builtin methods!
306 tmpsfi ... temporary stackframeinfo of current method
308 *******************************************************************************/
310 static inline void stacktrace_stackframeinfo_next(stackframeinfo_t *tmpsfi)
318 stackframeinfo_t *prevsfi;
322 assert(tmpsfi != NULL);
324 /* Get values from the stackframeinfo. */
332 /* Get the current stack frame size. */
334 framesize = *((uint32_t *) (((intptr_t) pv) + FrameSize));
336 /* Get the RA of the current stack frame (RA to the parent Java
337 method) if the current method is a non-leaf method. Otherwise
338 the value in the stackframeinfo is correct (from the signal
341 #if defined(ENABLE_JIT)
342 # if defined(ENABLE_INTRP)
344 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
348 if (!code_is_leafmethod(code))
349 ra = md_stacktrace_get_returnaddress(sp, framesize);
352 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
355 /* Get the PV for the parent Java method. */
357 #if defined(ENABLE_INTRP)
359 pv = codegen_get_pv_from_pc(ra);
363 #if defined(ENABLE_JIT)
364 # if defined(__SPARC_64__)
365 sp = md_get_framepointer(sp);
366 pv = md_get_pv_from_stackframe(sp);
368 pv = md_codegen_get_pv_from_pc(ra);
373 /* Get the codeinfo pointer for the parent Java method. */
375 code = code_get_codeinfo_for_pv(pv);
377 /* Calculate the SP for the parent Java method. */
379 #if defined(ENABLE_INTRP)
381 sp = *(u1 **) (sp - framesize);
385 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
386 sp = (void *) (((intptr_t) sp) + framesize + SIZEOF_VOID_P);
387 #elif defined(__SPARC_64__)
388 /* already has the new sp */
390 sp = (void *) (((intptr_t) sp) + framesize);
394 /* If the new codeinfo pointer is NULL we reached a
395 asm_vm_call_method function. In this case we get the next
396 values from the previous stackframeinfo in the chain.
397 Otherwise the new values have been calculated before. */
400 prevsfi = tmpsfi->prev;
402 /* If the previous stackframeinfo in the chain is NULL we
403 reached the top of the stacktrace. We set code and prev to
404 NULL to mark the end, which is checked in
405 stacktrace_stackframeinfo_end_check. */
407 if (prevsfi == NULL) {
413 /* Fill the temporary stackframeinfo with the new values. */
415 stacktrace_stackframeinfo_fill(tmpsfi, prevsfi);
418 /* Store the new values in the stackframeinfo. NOTE: We
419 subtract 1 from the RA to get the XPC, because the RA
420 points to the instruction after the call instruction. */
426 tmpsfi->xpc = (void *) (((intptr_t) ra) - 1);
430 /* Print current method information. */
432 if (opt_DebugStackTrace) {
434 log_print("[stacktrace: method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
435 tmpsfi->code->m, tmpsfi->pv, tmpsfi->sp, tmpsfi->ra,
437 method_print(tmpsfi->code->m);
445 /* stacktrace_stackframeinfo_end_check *****************************************
447 Check if we reached the end of the stacktrace.
450 tmpsfi ... temporary stackframeinfo of current method
453 true .... the end is reached
454 false ... the end is not reached
456 *******************************************************************************/
458 static inline bool stacktrace_stackframeinfo_end_check(stackframeinfo_t *tmpsfi)
462 assert(tmpsfi != NULL);
464 if ((tmpsfi->code == NULL) && (tmpsfi->prev == NULL)) {
466 if (opt_DebugStackTrace)
467 log_println("[stacktrace stop]");
477 /* stacktrace_depth ************************************************************
479 Calculates and returns the depth of the current stacktrace.
482 sfi ... stackframeinfo where to start the stacktrace
485 depth of the stacktrace
487 *******************************************************************************/
489 static int stacktrace_depth(stackframeinfo_t *sfi)
491 stackframeinfo_t tmpsfi;
496 if (opt_DebugStackTrace)
497 log_println("[stacktrace_depth]");
500 /* XXX This is not correct, but a workaround for threads-dump for
502 /* assert(sfi != NULL); */
506 /* Iterate over all stackframes. */
510 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
511 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
512 stacktrace_stackframeinfo_next(&tmpsfi)) {
513 /* Get methodinfo. */
517 /* Skip builtin methods. */
519 if (m->flags & ACC_METHOD_BUILTIN)
529 /* stacktrace_get **************************************************************
531 Builds and returns a stacktrace from the current thread for and
532 returns the stacktrace structure wrapped in a Java byte-array to
536 stacktrace as Java byte-array
538 *******************************************************************************/
540 java_handle_bytearray_t *stacktrace_get(void)
542 stackframeinfo_t *sfi;
543 stackframeinfo_t tmpsfi;
545 java_handle_bytearray_t *ba;
548 stacktrace_entry_t *ste;
550 bool skip_fillInStackTrace;
553 CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
556 if (opt_DebugStackTrace)
557 log_println("[stacktrace_get]");
560 skip_fillInStackTrace = true;
563 /* Get the stacktrace depth of the current thread. */
565 sfi = STACKFRAMEINFO;
567 depth = stacktrace_depth(sfi);
572 /* Allocate memory from the GC heap and copy the stacktrace
574 /* ATTENTION: Use a Java byte-array for this to not confuse the
576 /* FIXME: We waste some memory here as we skip some entries
579 ba_size = sizeof(stacktrace_t) + sizeof(stacktrace_entry_t) * depth;
581 ba = builtin_newarray_byte(ba_size);
586 /* Get a stacktrace entry pointer. */
587 /* ATTENTION: We need a critical section here because we use the
588 byte-array data pointer directly. */
592 st = (stacktrace_t *) LLNI_array_data(ba);
596 /* Iterate over the whole stack. */
598 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
599 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
600 stacktrace_stackframeinfo_next(&tmpsfi)) {
601 /* Get the methodinfo. */
605 /* Skip builtin methods. */
607 if (m->flags & ACC_METHOD_BUILTIN)
610 /* This logic is taken from
611 hotspot/src/share/vm/classfile/javaClasses.cpp
612 (java_lang_Throwable::fill_in_stack_trace). */
614 if (skip_fillInStackTrace == true) {
615 /* Check "fillInStackTrace" only once, so we negate the
616 flag after the first time check. */
618 #if defined(WITH_CLASSPATH_GNU)
619 /* For GNU Classpath we also need to skip
620 VMThrowable.fillInStackTrace(). */
622 if ((m->class == class_java_lang_VMThrowable) &&
623 (m->name == utf_fillInStackTrace))
627 skip_fillInStackTrace = false;
629 if (m->name == utf_fillInStackTrace)
633 /* Skip <init> methods of the exceptions klass. If there is
634 <init> methods that belongs to a superclass of the
635 exception we are going to skipping them in stack trace. */
637 if (skip_init == true) {
638 if (m->name == utf_init) {
639 /* throwable->is_a(method->method_holder())) { */
643 /* If no "Throwable.init()" method found, we stop
644 checking it next time. */
650 /* Store the stacktrace entry and increment the pointer. */
652 ste->code = tmpsfi.code;
653 ste->pc = tmpsfi.xpc;
658 /* Store the number of entries in the stacktrace structure. */
660 st->length = ste - st->entries;
664 /* release dump memory */
666 /* dump_release(dumpsize); */
668 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
673 /* dump_release(dumpsize); */
675 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
682 /* stacktrace_first_nonnull_classloader ****************************************
684 Returns the first non-null (user-defined) classloader on the stack.
685 If none is found NULL is returned.
690 *******************************************************************************/
692 classloader *stacktrace_first_nonnull_classloader(void)
694 stackframeinfo_t *sfi;
695 stackframeinfo_t tmpsfi;
700 if (opt_DebugStackTrace)
701 log_println("[stacktrace_first_nonnull_classloader]");
704 /* Get the stackframeinfo of the current thread. */
706 sfi = STACKFRAMEINFO;
708 /* Iterate over the whole stack. */
710 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
711 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
712 stacktrace_stackframeinfo_next(&tmpsfi)) {
715 cl = class_get_classloader(m->class);
725 /* stacktrace_getClassContext **************************************************
727 Creates a Class context array.
730 the array of java.lang.Class objects, or
731 NULL if an exception has been thrown
733 *******************************************************************************/
735 java_handle_objectarray_t *stacktrace_getClassContext(void)
737 stackframeinfo_t *sfi;
738 stackframeinfo_t tmpsfi;
740 java_handle_objectarray_t *oa;
741 java_object_t **data;
745 CYCLES_STATS_DECLARE_AND_START
748 if (opt_DebugStackTrace)
749 log_println("[stacktrace_getClassContext]");
752 sfi = STACKFRAMEINFO;
754 /* Get the depth of the current stack. */
756 depth = stacktrace_depth(sfi);
758 /* The first stackframe corresponds to the method whose
759 implementation calls this native function. We remove that
763 stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
764 stacktrace_stackframeinfo_next(&tmpsfi);
766 /* Allocate the Class array. */
768 oa = builtin_anewarray(depth, class_java_lang_Class);
771 CYCLES_STATS_END(stacktrace_getClassContext);
776 /* Fill the Class array from the stacktrace list. */
780 data = LLNI_array_data(oa);
782 /* Iterate over the whole stack. */
787 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
788 stacktrace_stackframeinfo_next(&tmpsfi)) {
789 /* Get methodinfo. */
793 /* Skip builtin methods. */
795 if (m->flags & ACC_METHOD_BUILTIN)
798 /* Store the class in the array. */
800 data[i] = (java_object_t *) m->class;
807 CYCLES_STATS_END(stacktrace_getClassContext)
813 /* stacktrace_getCurrentClass **************************************************
815 Find the current class by walking the stack trace.
817 Quote from the JNI documentation:
819 In the Java 2 Platform, FindClass locates the class loader
820 associated with the current native method. If the native code
821 belongs to a system class, no class loader will be
822 involved. Otherwise, the proper class loader will be invoked to
823 load and link the named class. When FindClass is called through the
824 Invocation Interface, there is no current native method or its
825 associated class loader. In that case, the result of
826 ClassLoader.getBaseClassLoader is used."
828 *******************************************************************************/
830 #if defined(ENABLE_JAVASE)
831 classinfo *stacktrace_get_current_class(void)
833 stackframeinfo_t *sfi;
834 stackframeinfo_t tmpsfi;
837 CYCLES_STATS_DECLARE_AND_START;
840 if (opt_DebugStackTrace)
841 log_println("[stacktrace_get_current_class]");
844 /* Get the stackframeinfo of the current thread. */
846 sfi = STACKFRAMEINFO;
848 /* If the stackframeinfo is NULL then FindClass is called through
849 the Invocation Interface and we return NULL */
852 CYCLES_STATS_END(stacktrace_getCurrentClass);
857 /* Iterate over the whole stack. */
859 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
860 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
861 stacktrace_stackframeinfo_next(&tmpsfi)) {
862 /* Get the methodinfo. */
866 if (m->class == class_java_security_PrivilegedAction) {
867 CYCLES_STATS_END(stacktrace_getCurrentClass);
872 if (m->class != NULL) {
873 CYCLES_STATS_END(stacktrace_getCurrentClass);
879 /* No Java method found on the stack. */
881 CYCLES_STATS_END(stacktrace_getCurrentClass);
885 #endif /* ENABLE_JAVASE */
888 /* stacktrace_get_stack ********************************************************
890 Create a 2-dimensional array for java.security.VMAccessControler.
894 NULL if an exception has been thrown
896 *******************************************************************************/
898 #if defined(ENABLE_JAVASE) && defined(WITH_CLASSPATH_GNU)
899 java_handle_objectarray_t *stacktrace_get_stack(void)
901 stackframeinfo_t *sfi;
902 stackframeinfo_t tmpsfi;
904 java_handle_objectarray_t *oa;
905 java_handle_objectarray_t *classes;
906 java_handle_objectarray_t *methodnames;
908 java_handle_t *string;
911 CYCLES_STATS_DECLARE_AND_START
914 if (opt_DebugStackTrace)
915 log_println("[stacktrace_get_stack]");
918 /* Get the stackframeinfo of the current thread. */
920 sfi = STACKFRAMEINFO;
922 /* Get the depth of the current stack. */
924 depth = stacktrace_depth(sfi);
929 /* Allocate the required arrays. */
931 oa = builtin_anewarray(2, arrayclass_java_lang_Object);
936 classes = builtin_anewarray(depth, class_java_lang_Class);
941 methodnames = builtin_anewarray(depth, class_java_lang_String);
943 if (methodnames == NULL)
946 /* Set up the 2-dimensional array. */
948 array_objectarray_element_set(oa, 0, (java_handle_t *) classes);
949 array_objectarray_element_set(oa, 1, (java_handle_t *) methodnames);
951 /* Iterate over the whole stack. */
952 /* TODO We should use a critical section here to speed things
957 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
958 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
959 stacktrace_stackframeinfo_next(&tmpsfi)) {
960 /* Get the methodinfo. */
964 /* Skip builtin methods. */
966 if (m->flags & ACC_METHOD_BUILTIN)
969 /* Store the class in the array. */
970 /* NOTE: We use a LLNI-macro here, because a classinfo is not
973 LLNI_array_direct(classes, i) = (java_object_t *) m->class;
975 /* Store the name in the array. */
977 string = javastring_new(m->name);
982 array_objectarray_element_set(methodnames, i, string);
987 CYCLES_STATS_END(stacktrace_get_stack)
992 CYCLES_STATS_END(stacktrace_get_stack)
999 /* stacktrace_print ************************************************************
1001 Print the given stacktrace with CACAO intern methods only (no Java
1004 This method is used by stacktrace_dump_trace and
1005 builtin_trace_exception.
1008 st ... stacktrace to print
1010 *******************************************************************************/
1012 void stacktrace_print(stacktrace_t *st)
1014 stacktrace_entry_t *ste;
1019 ste = &(st->entries[0]);
1021 for (i = 0; i < st->length; i++, ste++) {
1024 /* Get the line number. */
1026 linenumber = linenumbertable_linenumber_for_pc(&m, ste->code, ste->pc);
1029 utf_display_printable_ascii_classname(m->class->name);
1031 utf_display_printable_ascii(m->name);
1032 utf_display_printable_ascii(m->descriptor);
1034 if (m->flags & ACC_NATIVE) {
1035 puts("(Native Method)");
1039 utf_display_printable_ascii(m->class->sourcefile);
1040 printf(":%d)\n", linenumber);
1044 /* just to be sure */
1050 /* stacktrace_print_exception **************************************************
1052 Print the stacktrace of a given exception (more or less a wrapper
1053 to stacktrace_print).
1056 h ... handle of exception to print
1058 *******************************************************************************/
1060 void stacktrace_print_exception(java_handle_t *h)
1062 java_lang_Throwable *o;
1064 #if defined(WITH_CLASSPATH_GNU)
1065 java_lang_VMThrowable *vmt;
1066 gnu_classpath_Pointer *backtrace;
1067 #elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
1068 java_lang_Object *backtrace;
1071 java_handle_bytearray_t *ba;
1074 o = (java_lang_Throwable *) h;
1079 /* now print the stacktrace */
1081 #if defined(WITH_CLASSPATH_GNU)
1083 LLNI_field_get_ref(o, vmState, vmt);
1084 LLNI_field_get_ref(vmt, vmData, backtrace);
1086 #elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
1088 LLNI_field_get_ref(o, backtrace, backtrace);
1091 # error unknown classpath configuration
1094 ba = (java_handle_bytearray_t *) backtrace;
1100 /* We need a critical section here as we use the byte-array data
1101 pointer directly. */
1103 LLNI_CRITICAL_START;
1105 st = (stacktrace_t *) LLNI_array_data(ba);
1107 stacktrace_print(st);
1113 #if defined(ENABLE_CYCLES_STATS)
1114 void stacktrace_print_cycles_stats(FILE *file)
1116 CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead, file);
1117 CYCLES_STATS_PRINT(stacktrace_get, file);
1118 CYCLES_STATS_PRINT(stacktrace_getClassContext , file);
1119 CYCLES_STATS_PRINT(stacktrace_getCurrentClass , file);
1120 CYCLES_STATS_PRINT(stacktrace_get_stack, file);
1126 * These are local overrides for various environment variables in Emacs.
1127 * Please do not remove this and leave it at the end of the file, where
1128 * Emacs will automagically detect them.
1129 * ---------------------------------------------------------------------
1132 * indent-tabs-mode: t
1136 * vim:noexpandtab:sw=4:ts=4: