1 /* src/vm/jit/stacktrace.cpp - machine independent stacktrace system
3 Copyright (C) 1996-2005, 2006, 2007, 2008
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5 Copyright (C) 2009 Theobroma Systems Ltd.
7 This file is part of CACAO.
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2, or (at
12 your option) any later version.
14 This program is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
40 #include "mm/memory.hpp"
42 #include "vm/jit/stacktrace.hpp"
44 #include "native/llni.h"
46 #include "threads/thread.hpp"
48 #include "toolbox/logging.hpp"
50 #include "vm/array.hpp"
51 #include "vm/jit/builtin.hpp"
52 #include "vm/class.hpp"
53 #include "vm/cycles-stats.h"
54 #include "vm/exceptions.hpp"
55 #include "vm/globals.hpp"
56 #include "vm/javaobjects.hpp"
57 #include "vm/loader.hpp"
58 #include "vm/method.hpp"
59 #include "vm/options.h"
60 #include "vm/string.hpp"
63 #include "vm/jit/asmpart.h"
64 #include "vm/jit/codegen-common.hpp"
65 #include "vm/jit/linenumbertable.hpp"
66 #include "vm/jit/methodheader.h"
67 #include "vm/jit/methodtree.h"
70 // FIXME Use C-linkage for now.
73 /* global variables ***********************************************************/
75 CYCLES_STATS_DECLARE(stacktrace_overhead , 100, 1)
76 CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace, 40, 5000)
77 CYCLES_STATS_DECLARE(stacktrace_get, 40, 5000)
78 CYCLES_STATS_DECLARE(stacktrace_getClassContext , 40, 5000)
79 CYCLES_STATS_DECLARE(stacktrace_getCurrentClass , 40, 5000)
80 CYCLES_STATS_DECLARE(stacktrace_get_stack , 40, 10000)
83 /* stacktrace_stackframeinfo_add ***********************************************
85 Fills a stackframe info structure with the given or calculated
86 values and adds it to the chain.
88 *******************************************************************************/
90 void stacktrace_stackframeinfo_add(stackframeinfo_t* sfi, void* pv, void* sp, void* ra, void* xpc)
92 stackframeinfo_t *currentsfi;
94 #if defined(ENABLE_JIT)
98 /* Get current stackframe info. */
100 currentsfi = threads_get_current_stackframeinfo();
102 /* sometimes we don't have pv handy (e.g. in asmpart.S:
103 L_asm_call_jit_compiler_exception or in the interpreter). */
106 #if defined(ENABLE_INTRP)
108 pv = methodtree_find(ra);
112 #if defined(ENABLE_JIT)
113 # if defined(__SPARC_64__)
114 pv = md_get_pv_from_stackframe(sp);
116 pv = md_codegen_get_pv_from_pc(ra);
122 /* Get codeinfo pointer for the parent Java method. */
124 code = code_get_codeinfo_for_pv(pv);
127 /* assert(m != NULL); */
129 #if defined(ENABLE_JIT)
130 # if defined(ENABLE_INTRP)
131 /* When using the interpreter, we pass RA to the function. */
135 # if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__M68K__)
136 /* On i386 and x86_64 we always have to get the return address
138 /* m68k has return address on stack always */
139 /* On S390 we use REG_RA as REG_ITMP3, so we have always to get
140 the RA from stack. */
142 framesize = md_stacktrace_get_framesize(code);
144 ra = md_stacktrace_get_returnaddress(sp, framesize);
146 /* If the method is a non-leaf function, we need to get the
147 return address from the stack. For leaf functions the
148 return address is set correctly. This makes the assembler
149 and the signal handler code simpler. The code is NULL is
150 the asm_vm_call_method special case. */
152 if ((code == NULL) || !code_is_leafmethod(code)) {
153 framesize = md_stacktrace_get_framesize(code);
155 ra = md_stacktrace_get_returnaddress(sp, framesize);
158 # if defined(ENABLE_INTRP)
163 /* Calculate XPC when not given. The XPC is then the return
164 address of the current method minus 1 because the RA points to
165 the instruction after the call instruction. This is required
166 e.g. for method stubs. */
169 xpc = (void *) (((intptr_t) ra) - 1);
172 /* Fill new stackframeinfo structure. */
174 sfi->prev = currentsfi;
182 if (opt_DebugStackFrameInfo) {
184 log_print("[stackframeinfo add : sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
185 sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
186 method_print(sfi->code->m);
192 /* Store new stackframeinfo pointer. */
194 threads_set_current_stackframeinfo(sfi);
196 /* set the native world flag for the current thread */
197 /* ATTENTION: This flag tells the GC how to treat this thread in case of
198 a collection. Set this flag _after_ a valid stackframe info was set. */
200 THREAD_NATIVEWORLD_ENTER;
204 /* stacktrace_stackframeinfo_remove ********************************************
206 Remove the given stackframeinfo from the chain in the current
209 *******************************************************************************/
211 void stacktrace_stackframeinfo_remove(stackframeinfo_t *sfi)
213 /* Clear the native world flag for the current thread. */
214 /* ATTENTION: Clear this flag _before_ removing the stackframe info. */
216 THREAD_NATIVEWORLD_EXIT;
219 if (opt_DebugStackFrameInfo) {
221 log_print("[stackframeinfo remove: sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
222 sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
223 method_print(sfi->code->m);
229 /* Set previous stackframe info. */
231 threads_set_current_stackframeinfo(sfi->prev);
235 /* stacktrace_stackframeinfo_fill **********************************************
237 Fill the temporary stackframeinfo structure with the values given
241 tmpsfi ... temporary stackframeinfo
242 sfi ...... stackframeinfo to be used in the next iteration
244 *******************************************************************************/
246 static inline void stacktrace_stackframeinfo_fill(stackframeinfo_t *tmpsfi, stackframeinfo_t *sfi)
250 assert(tmpsfi != NULL);
253 /* Fill the temporary stackframeinfo. */
255 tmpsfi->code = sfi->code;
256 tmpsfi->pv = sfi->pv;
257 tmpsfi->sp = sfi->sp;
258 tmpsfi->ra = sfi->ra;
259 tmpsfi->xpc = sfi->xpc;
261 /* Set the previous stackframe info of the temporary one to the
262 next in the chain. */
264 tmpsfi->prev = sfi->prev;
267 if (opt_DebugStackTrace)
268 log_println("[stacktrace fill]");
273 /* stacktrace_stackframeinfo_next **********************************************
275 Walk the stack (or the stackframeinfo-chain) to the next method and
276 return the new stackframe values in the temporary stackframeinfo
279 ATTENTION: This function does NOT skip builtin methods!
282 tmpsfi ... temporary stackframeinfo of current method
284 *******************************************************************************/
286 static inline void stacktrace_stackframeinfo_next(stackframeinfo_t *tmpsfi)
294 stackframeinfo_t *prevsfi;
298 assert(tmpsfi != NULL);
300 /* Get values from the stackframeinfo. */
308 /* Get the current stack frame size. */
310 framesize = md_stacktrace_get_framesize(code);
312 /* Get the RA of the current stack frame (RA to the parent Java
313 method) if the current method is a non-leaf method. Otherwise
314 the value in the stackframeinfo is correct (from the signal
317 #if defined(ENABLE_JIT)
318 # if defined(ENABLE_INTRP)
320 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
324 if (!code_is_leafmethod(code))
325 ra = md_stacktrace_get_returnaddress(sp, framesize);
328 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
331 /* Get the PV for the parent Java method. */
333 #if defined(ENABLE_INTRP)
335 pv = methodtree_find(ra);
339 #if defined(ENABLE_JIT)
340 # if defined(__SPARC_64__)
341 sp = md_get_framepointer(sp);
342 pv = md_get_pv_from_stackframe(sp);
344 pv = md_codegen_get_pv_from_pc(ra);
349 /* Get the codeinfo pointer for the parent Java method. */
351 code = code_get_codeinfo_for_pv(pv);
353 /* Calculate the SP for the parent Java method. */
355 #if defined(ENABLE_INTRP)
357 sp = *(u1 **) (sp - framesize);
361 #if STACKFRMAE_RA_BETWEEN_FRAMES
362 sp = (void *) (((intptr_t) sp) + framesize + SIZEOF_VOID_P);
363 #elif defined(__SPARC_64__)
364 /* already has the new sp */
366 sp = (void *) (((intptr_t) sp) + framesize);
370 /* If the new codeinfo pointer is NULL we reached a
371 asm_vm_call_method function. In this case we get the next
372 values from the previous stackframeinfo in the chain.
373 Otherwise the new values have been calculated before. */
376 prevsfi = tmpsfi->prev;
378 /* If the previous stackframeinfo in the chain is NULL we
379 reached the top of the stacktrace. We set code and prev to
380 NULL to mark the end, which is checked in
381 stacktrace_stackframeinfo_end_check. */
383 if (prevsfi == NULL) {
389 /* Fill the temporary stackframeinfo with the new values. */
391 stacktrace_stackframeinfo_fill(tmpsfi, prevsfi);
394 /* Store the new values in the stackframeinfo. NOTE: We
395 subtract 1 from the RA to get the XPC, because the RA
396 points to the instruction after the call instruction. */
402 tmpsfi->xpc = (void *) (((intptr_t) ra) - 1);
406 /* Print current method information. */
408 if (opt_DebugStackTrace) {
410 log_print("[stacktrace: method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
411 tmpsfi->code->m, tmpsfi->pv, tmpsfi->sp, tmpsfi->ra,
413 method_print(tmpsfi->code->m);
421 /* stacktrace_stackframeinfo_end_check *****************************************
423 Check if we reached the end of the stacktrace.
426 tmpsfi ... temporary stackframeinfo of current method
429 true .... the end is reached
430 false ... the end is not reached
432 *******************************************************************************/
434 static inline bool stacktrace_stackframeinfo_end_check(stackframeinfo_t *tmpsfi)
438 assert(tmpsfi != NULL);
440 if ((tmpsfi->code == NULL) && (tmpsfi->prev == NULL)) {
442 if (opt_DebugStackTrace)
443 log_println("[stacktrace stop]");
453 /* stacktrace_depth ************************************************************
455 Calculates and returns the depth of the current stacktrace.
458 sfi ... stackframeinfo where to start the stacktrace
461 depth of the stacktrace
463 *******************************************************************************/
465 static int stacktrace_depth(stackframeinfo_t *sfi)
467 stackframeinfo_t tmpsfi;
472 if (opt_DebugStackTrace)
473 log_println("[stacktrace_depth]");
476 /* XXX This is not correct, but a workaround for threads-dump for
478 /* assert(sfi != NULL); */
482 /* Iterate over all stackframes. */
486 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
487 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
488 stacktrace_stackframeinfo_next(&tmpsfi)) {
489 /* Get methodinfo. */
493 /* Skip builtin methods. */
495 if (m->flags & ACC_METHOD_BUILTIN)
505 /* stacktrace_get **************************************************************
507 Builds and returns a stacktrace starting from the given stackframe
508 info and returns the stacktrace structure wrapped in a Java
509 byte-array to not confuse the GC.
512 sfi ... stackframe info to start stacktrace from
515 stacktrace as Java byte-array
517 *******************************************************************************/
519 java_handle_bytearray_t *stacktrace_get(stackframeinfo_t *sfi)
521 stackframeinfo_t tmpsfi;
525 stacktrace_entry_t *ste;
527 bool skip_fillInStackTrace;
530 CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
533 if (opt_DebugStackTrace)
534 log_println("[stacktrace_get]");
537 skip_fillInStackTrace = true;
540 depth = stacktrace_depth(sfi);
545 /* Allocate memory from the GC heap and copy the stacktrace
547 /* ATTENTION: Use a Java byte-array for this to not confuse the
549 /* FIXME: We waste some memory here as we skip some entries
552 ba_size = sizeof(stacktrace_t) + sizeof(stacktrace_entry_t) * depth;
554 ByteArray ba(ba_size);
559 /* Get a stacktrace entry pointer. */
560 /* ATTENTION: We need a critical section here because we use the
561 byte-array data pointer directly. */
565 st = (stacktrace_t *) ba.get_raw_data_ptr();
569 /* Iterate over the whole stack. */
571 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
572 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
573 stacktrace_stackframeinfo_next(&tmpsfi)) {
574 /* Get the methodinfo. */
578 /* Skip builtin methods. */
580 if (m->flags & ACC_METHOD_BUILTIN)
583 /* This logic is taken from
584 hotspot/src/share/vm/classfile/javaClasses.cpp
585 (java_lang_Throwable::fill_in_stack_trace). */
587 if (skip_fillInStackTrace == true) {
588 /* Check "fillInStackTrace" only once, so we negate the
589 flag after the first time check. */
591 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
592 /* For GNU Classpath we also need to skip
593 VMThrowable.fillInStackTrace(). */
595 if ((m->clazz == class_java_lang_VMThrowable) &&
596 (m->name == utf_fillInStackTrace))
600 skip_fillInStackTrace = false;
602 if (m->name == utf_fillInStackTrace)
606 /* Skip <init> methods of the exceptions klass. If there is
607 <init> methods that belongs to a superclass of the
608 exception we are going to skipping them in stack trace. */
610 if (skip_init == true) {
611 if ((m->name == utf_init) &&
612 (class_issubclass(m->clazz, class_java_lang_Throwable))) {
616 /* If no "Throwable.init()" method found, we stop
617 checking it next time. */
623 /* Store the stacktrace entry and increment the pointer. */
625 ste->code = tmpsfi.code;
626 ste->pc = tmpsfi.xpc;
631 /* Store the number of entries in the stacktrace structure. */
633 st->length = ste - st->entries;
637 /* release dump memory */
639 /* dump_release(dumpsize); */
641 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
643 return ba.get_handle();
646 /* dump_release(dumpsize); */
648 CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
655 /* stacktrace_get_current ******************************************************
657 Builds and returns a stacktrace from the current thread and returns
658 the stacktrace structure wrapped in a Java byte-array to not
662 stacktrace as Java byte-array
664 *******************************************************************************/
666 java_handle_bytearray_t *stacktrace_get_current(void)
668 stackframeinfo_t *sfi;
669 java_handle_bytearray_t *ba;
671 sfi = threads_get_current_stackframeinfo();
672 ba = stacktrace_get(sfi);
679 * Creates a java.lang.StackTraceElement for one element of the given
682 * @param st Given stacktrace.
683 * @param index Index of element inside stacktrace.
684 * @return The filled StackTraceElement object.
686 #if defined(ENABLE_JAVASE)
687 java_handle_t* stacktrace_get_StackTraceElement(stacktrace_t* st, int32_t index)
691 if ((index < 0) || (index >= st->length)) {
692 /* XXX This should be an IndexOutOfBoundsException (check this
694 exceptions_throw_arrayindexoutofboundsexception();
698 // Get the stacktrace entry.
699 stacktrace_entry_t* ste = &(st->entries[index]);
701 // Get the codeinfo, methodinfo and classinfo.
702 codeinfo* code = ste->code;
703 methodinfo* m = code->m;
704 classinfo* c = m->clazz;
707 java_handle_t* filename;
709 if (!(m->flags & ACC_NATIVE)) {
710 if (c->sourcefile != NULL)
711 filename = javastring_new(c->sourcefile);
721 if (m->flags & ACC_NATIVE) {
722 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
724 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
727 # error unknown classpath configuration
731 // FIXME linenumbertable->find could change the methodinfo
732 // pointer when hitting an inlined method.
733 linenumber = code->linenumbertable->find(&m, ste->pc);
734 linenumber = (linenumber == 0) ? -1 : linenumber;
737 // Get declaring class name.
738 java_handle_t* declaringclass = class_get_classname(c);
740 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
741 // Allocate a new StackTraceElement object.
742 java_handle_t* h = builtin_new(class_java_lang_StackTraceElement);
747 java_lang_StackTraceElement jlste(h, filename, linenumber, declaringclass, javastring_new(m->name), ((m->flags & ACC_NATIVE) ? 1 : 0));
748 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
749 // Allocate a new StackTraceElement object.
750 java_lang_StackTraceElement jlste(declaringclass, javastring_new(m->name), filename, linenumber);
755 # error unknown classpath configuration
758 return jlste.get_handle();
764 * Creates a complete array of java.lang.StackTraceElement objects
765 * for the given stacktrace.
767 * @param st Given stacktrace.
768 * @return Array of filled StackTraceElement objects.
770 #if defined(ENABLE_JAVASE)
771 java_handle_objectarray_t* stacktrace_get_StackTraceElements(stacktrace_t* st)
773 // Get length of stacktrace. If stacktrace is not available
774 // an empty array should be returned.
775 int32_t length = (st != NULL) ? st->length : 0;
777 // Create the stacktrace element array.
778 ObjectArray oa(length, class_java_lang_StackTraceElement);
783 // Iterate over all stacktrace elements.
784 for (int i = 0; i < length; i++) {
786 // Get stacktrace element at current index.
787 java_handle_t* h = stacktrace_get_StackTraceElement(st, i);
792 // Store stacktrace element in array.
793 oa.set_element(i, h);
796 return oa.get_handle();
801 /* stacktrace_get_caller_class *************************************************
803 Get the class on the stack at the given depth. This function skips
804 various special classes or methods.
807 depth ... depth to get caller class of
812 *******************************************************************************/
814 #if defined(ENABLE_JAVASE)
815 classinfo *stacktrace_get_caller_class(int depth)
817 stackframeinfo_t *sfi;
818 stackframeinfo_t tmpsfi;
824 if (opt_DebugStackTrace)
825 log_println("[stacktrace_get_caller_class]");
828 /* Get the stackframeinfo of the current thread. */
830 sfi = threads_get_current_stackframeinfo();
832 /* Iterate over the whole stack until we reached the requested
837 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
838 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
839 stacktrace_stackframeinfo_next(&tmpsfi)) {
844 /* Skip builtin methods. */
846 if (m->flags & ACC_METHOD_BUILTIN)
849 #if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
850 /* NOTE: See hotspot/src/share/vm/runtime/vframe.cpp
851 (vframeStreamCommon::security_get_caller_frame). */
853 /* This is java.lang.reflect.Method.invoke(), skip it. */
855 if (m == method_java_lang_reflect_Method_invoke)
858 /* This is an auxiliary frame, skip it. */
860 if (class_issubclass(c, class_sun_reflect_MagicAccessorImpl))
864 /* We reached the requested depth. */
878 * Returns the first non-null (user-defined) classloader on the stack.
880 * @return The first non-null classloader or NULL if none is found.
882 classloader_t* stacktrace_first_nonnull_classloader(void)
884 stackframeinfo_t *sfi;
885 stackframeinfo_t tmpsfi;
890 if (opt_DebugStackTrace)
891 log_println("[stacktrace_first_nonnull_classloader]");
894 /* Get the stackframeinfo of the current thread. */
896 sfi = threads_get_current_stackframeinfo();
898 /* Iterate over the whole stack. */
900 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
901 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
902 stacktrace_stackframeinfo_next(&tmpsfi)) {
905 cl = class_get_classloader(m->clazz);
916 * Checks if a given classloader is equal to the the second classloader
917 * or one of its ancestors (parents).
919 * XXX: This helper method should be moved to java_lang_Classloader.
921 #if defined(ENABLE_JAVASE)
922 static bool is_ancestor_of(classloader_t* loader, classloader_t* parent)
924 // Iterate over chain of possible parents.
925 while (parent != NULL) {
927 // Check if given loader is parent.
928 if (loader == parent)
931 // Jump to next parent.
932 java_lang_ClassLoader jlcl(parent);
933 parent = jlcl.get_parent();
938 #endif /* defined(ENABLE_JAVASE) */
942 * Returns the first non-system (user-defined) classloader on the stack.
943 * A non-system classloader is a non-null classloader being not equal to
944 * the system classloader (or one of its ancestors).
946 * @return The first non-system classloader or NULL if none is found.
948 #if defined(ENABLE_JAVASE)
949 classloader_t* stacktrace_first_nonsystem_classloader(void)
951 stackframeinfo_t *sfi;
952 stackframeinfo_t tmpsfi;
955 classloader_t *syscl;
958 if (opt_DebugStackTrace)
959 log_println("[stacktrace_first_nonsystem_classloader]");
962 // Get the stackframeinfo of the current thread.
963 sfi = threads_get_current_stackframeinfo();
965 // Get the system class class loader.
966 syscl = java_lang_ClassLoader::invoke_getSystemClassLoader();
968 // Iterate over the whole stack.
969 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
970 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
971 stacktrace_stackframeinfo_next(&tmpsfi)) {
974 cl = class_get_classloader(m->clazz);
979 // XXX if a method in a class in a trusted loader is in a
980 // doPrivileged, return NULL (or break) here.
982 if (!is_ancestor_of(cl, syscl))
988 #endif /* defined(ENABLE_JAVASE) */
991 /* stacktrace_getClassContext **************************************************
993 Creates a Class context array.
996 the array of java.lang.Class objects, or
997 NULL if an exception has been thrown
999 *******************************************************************************/
1001 java_handle_objectarray_t *stacktrace_getClassContext(void)
1003 stackframeinfo_t *sfi;
1004 stackframeinfo_t tmpsfi;
1009 CYCLES_STATS_DECLARE_AND_START
1011 #if !defined(NDEBUG)
1012 if (opt_DebugStackTrace)
1013 log_println("[stacktrace_getClassContext]");
1016 sfi = threads_get_current_stackframeinfo();
1018 /* Get the depth of the current stack. */
1020 depth = stacktrace_depth(sfi);
1022 /* The first stackframe corresponds to the method whose
1023 implementation calls this native function. We remove that
1027 stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1028 stacktrace_stackframeinfo_next(&tmpsfi);
1030 /* Allocate the Class array. */
1032 ClassArray ca(depth);
1035 CYCLES_STATS_END(stacktrace_getClassContext);
1040 /* Fill the Class array from the stacktrace list. */
1041 /* Iterate over the whole stack. */
1046 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1047 stacktrace_stackframeinfo_next(&tmpsfi)) {
1048 /* Get methodinfo. */
1052 /* Skip builtin methods. */
1054 if (m->flags & ACC_METHOD_BUILTIN)
1057 /* Store the class in the array. */
1059 ca.set_element(i, m->clazz);
1066 CYCLES_STATS_END(stacktrace_getClassContext)
1068 return ca.get_handle();
1072 /* stacktrace_getCurrentClass **************************************************
1074 Find the current class by walking the stack trace.
1076 Quote from the JNI documentation:
1078 In the Java 2 Platform, FindClass locates the class loader
1079 associated with the current native method. If the native code
1080 belongs to a system class, no class loader will be
1081 involved. Otherwise, the proper class loader will be invoked to
1082 load and link the named class. When FindClass is called through the
1083 Invocation Interface, there is no current native method or its
1084 associated class loader. In that case, the result of
1085 ClassLoader.getBaseClassLoader is used."
1087 *******************************************************************************/
1089 #if defined(ENABLE_JAVASE)
1090 classinfo *stacktrace_get_current_class(void)
1092 stackframeinfo_t *sfi;
1093 stackframeinfo_t tmpsfi;
1096 CYCLES_STATS_DECLARE_AND_START;
1098 #if !defined(NDEBUG)
1099 if (opt_DebugStackTrace)
1100 log_println("[stacktrace_get_current_class]");
1103 /* Get the stackframeinfo of the current thread. */
1105 sfi = threads_get_current_stackframeinfo();
1107 /* If the stackframeinfo is NULL then FindClass is called through
1108 the Invocation Interface and we return NULL */
1111 CYCLES_STATS_END(stacktrace_getCurrentClass);
1116 /* Iterate over the whole stack. */
1118 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1119 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1120 stacktrace_stackframeinfo_next(&tmpsfi)) {
1121 /* Get the methodinfo. */
1125 if (m->clazz == class_java_security_PrivilegedAction) {
1126 CYCLES_STATS_END(stacktrace_getCurrentClass);
1131 if (m->clazz != NULL) {
1132 CYCLES_STATS_END(stacktrace_getCurrentClass);
1138 /* No Java method found on the stack. */
1140 CYCLES_STATS_END(stacktrace_getCurrentClass);
1144 #endif /* ENABLE_JAVASE */
1147 /* stacktrace_get_stack ********************************************************
1149 Create a 2-dimensional array for java.security.VMAccessControler.
1153 NULL if an exception has been thrown
1155 *******************************************************************************/
1157 #if defined(ENABLE_JAVASE) && defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
1158 java_handle_objectarray_t *stacktrace_get_stack(void)
1160 stackframeinfo_t *sfi;
1161 stackframeinfo_t tmpsfi;
1164 java_handle_t *string;
1167 CYCLES_STATS_DECLARE_AND_START
1169 #if !defined(NDEBUG)
1170 if (opt_DebugStackTrace)
1171 log_println("[stacktrace_get_stack]");
1174 /* Get the stackframeinfo of the current thread. */
1176 sfi = threads_get_current_stackframeinfo();
1178 /* Get the depth of the current stack. */
1180 depth = stacktrace_depth(sfi);
1185 /* Allocate the required arrays. */
1187 ObjectArray oa(2, arrayclass_java_lang_Object);
1188 ClassArray classes(depth);
1189 ObjectArray methodnames(depth, class_java_lang_String);
1194 if (classes.is_null())
1197 if (methodnames.is_null())
1200 /* Set up the 2-dimensional array. */
1202 oa.set_element(0, (java_handle_t *) classes.get_handle());
1203 oa.set_element(1, (java_handle_t *) methodnames.get_handle());
1205 /* Iterate over the whole stack. */
1206 /* TODO We should use a critical section here to speed things
1211 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1212 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1213 stacktrace_stackframeinfo_next(&tmpsfi)) {
1214 /* Get the methodinfo. */
1218 /* Skip builtin methods. */
1220 if (m->flags & ACC_METHOD_BUILTIN)
1223 /* Store the class in the array. */
1225 classes.set_element(i, m->clazz);
1227 /* Store the name in the array. */
1229 string = javastring_new(m->name);
1234 methodnames.set_element(i, string);
1239 CYCLES_STATS_END(stacktrace_get_stack)
1241 return oa.get_handle();
1244 CYCLES_STATS_END(stacktrace_get_stack)
1251 /* stacktrace_print_entry ****************************************************
1253 Print line for a stacktrace entry.
1256 m ............ methodinfo of the entry
1257 linenumber ... linenumber of the entry
1259 *******************************************************************************/
1261 static void stacktrace_print_entry(methodinfo *m, int32_t linenumber)
1269 if (m->flags & ACC_METHOD_BUILTIN)
1272 utf_display_printable_ascii_classname(m->clazz->name);
1275 utf_display_printable_ascii(m->name);
1276 utf_display_printable_ascii(m->descriptor);
1278 if (m->flags & ACC_NATIVE) {
1279 puts("(Native Method)");
1282 if (m->flags & ACC_METHOD_BUILTIN) {
1287 utf_display_printable_ascii(m->clazz->sourcefile);
1288 printf(":%d)\n", linenumber);
1296 /* stacktrace_print ************************************************************
1298 Print the given stacktrace with CACAO intern methods only (no Java
1301 This method is used by stacktrace_dump_trace and
1302 builtin_trace_exception.
1305 st ... stacktrace to print
1307 *******************************************************************************/
1309 void stacktrace_print(stacktrace_t *st)
1311 stacktrace_entry_t *ste;
1316 ste = &(st->entries[0]);
1318 for (i = 0; i < st->length; i++, ste++) {
1321 /* Get the line number. */
1323 linenumber = ste->code->linenumbertable->find(&m, ste->pc);
1325 stacktrace_print_entry(m, linenumber);
1330 /* stacktrace_print_current ****************************************************
1332 Print the current stacktrace of the current thread.
1334 NOTE: This function prints all frames of the stacktrace and does
1335 not skip frames like stacktrace_get.
1337 *******************************************************************************/
1339 void stacktrace_print_current(void)
1341 stackframeinfo_t *sfi;
1342 stackframeinfo_t tmpsfi;
1347 sfi = threads_get_current_stackframeinfo();
1350 puts("\t<<No stacktrace available>>");
1355 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1356 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1357 stacktrace_stackframeinfo_next(&tmpsfi)) {
1358 /* Get the methodinfo. */
1363 // Get the line number.
1364 linenumber = code->linenumbertable->find(&m, tmpsfi.xpc);
1366 stacktrace_print_entry(m, linenumber);
1372 * Creates a stacktrace for the given thread.
1374 * @param t Given thread.
1375 * @return Current stacktrace of the given thread.
1377 * XXX: Creation of the stacktrace starts at the most recent
1378 * stackframeinfo block. If the thread is not inside the native
1379 * world, the created stacktrace is not complete!
1381 #if defined(ENABLE_THREADS)
1382 stacktrace_t* stacktrace_get_of_thread(threadobject* t)
1384 stackframeinfo_t* sfi;
1385 java_handle_bytearray_t* stba;
1388 sfi = t->_stackframeinfo;
1389 stba = stacktrace_get(sfi);
1396 st = (stacktrace_t*) ba.get_raw_data_ptr();
1403 /* stacktrace_print_of_thread **************************************************
1405 Print the current stacktrace of the given thread.
1410 *******************************************************************************/
1412 #if defined(ENABLE_THREADS)
1413 void stacktrace_print_of_thread(threadobject *t)
1415 stackframeinfo_t *sfi;
1416 stackframeinfo_t tmpsfi;
1421 /* Build a stacktrace for the passed thread. */
1423 sfi = t->_stackframeinfo;
1426 puts("\t<<No stacktrace available>>");
1431 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1432 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1433 stacktrace_stackframeinfo_next(&tmpsfi)) {
1434 /* Get the methodinfo. */
1439 // Get the line number.
1440 linenumber = code->linenumbertable->find(&m, tmpsfi.xpc);
1442 stacktrace_print_entry(m, linenumber);
1448 /* stacktrace_print_exception **************************************************
1450 Print the stacktrace of a given exception (more or less a wrapper
1451 to stacktrace_print).
1454 h ... handle of exception to print
1456 *******************************************************************************/
1458 void stacktrace_print_exception(java_handle_t *h)
1463 java_lang_Throwable t(h);
1465 /* now print the stacktrace */
1467 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
1469 java_lang_VMThrowable vmt(t.get_vmState());
1470 ByteArray backtrace(vmt.get_vmdata());
1472 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) || defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
1474 ByteArray backtrace(t.get_backtrace());
1477 # error unknown classpath configuration
1482 assert(backtrace.is_non_null());
1484 /* We need a critical section here as we use the byte-array data
1485 pointer directly. */
1487 LLNI_CRITICAL_START;
1489 stacktrace_t* st = (stacktrace_t*) backtrace.get_raw_data_ptr();
1491 stacktrace_print(st);
1497 #if defined(ENABLE_CYCLES_STATS)
1498 void stacktrace_print_cycles_stats(FILE *file)
1500 CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead, file);
1501 CYCLES_STATS_PRINT(stacktrace_get, file);
1502 CYCLES_STATS_PRINT(stacktrace_getClassContext , file);
1503 CYCLES_STATS_PRINT(stacktrace_getCurrentClass , file);
1504 CYCLES_STATS_PRINT(stacktrace_get_stack, file);
1512 * These are local overrides for various environment variables in Emacs.
1513 * Please do not remove this and leave it at the end of the file, where
1514 * Emacs will automagically detect them.
1515 * ---------------------------------------------------------------------
1518 * indent-tabs-mode: t
1522 * vim:noexpandtab:sw=4:ts=4: