1 /* src/vm/jit/stacktrace.cpp - machine independent stacktrace system
3 Copyright (C) 1996-2011
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);
907 #if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
908 /* NOTE: See hotspot/src/share/vm/runtime/vframe.cpp
909 (vframeStreamCommon::skip_reflection_related_frames). */
910 if (class_issubclass(m->clazz, class_sun_reflect_MethodAccessorImpl) ||
911 class_issubclass(m->clazz, class_sun_reflect_ConstructorAccessorImpl))
924 * Checks if a given classloader is equal to the the second classloader
925 * or one of its ancestors (parents).
927 * XXX: This helper method should be moved to java_lang_Classloader.
929 #if defined(ENABLE_JAVASE)
930 static bool is_ancestor_of(classloader_t* loader, classloader_t* parent)
932 // Iterate over chain of possible parents.
933 while (parent != NULL) {
935 // Check if given loader is parent.
936 if (loader == parent)
939 // Jump to next parent.
940 java_lang_ClassLoader jlcl(parent);
941 parent = jlcl.get_parent();
946 #endif /* defined(ENABLE_JAVASE) */
950 * Returns the first non-system (user-defined) classloader on the stack.
951 * A non-system classloader is a non-null classloader being not equal to
952 * the system classloader (or one of its ancestors).
954 * @return The first non-system classloader or NULL if none is found.
956 #if defined(ENABLE_JAVASE)
957 classloader_t* stacktrace_first_nonsystem_classloader(void)
959 stackframeinfo_t *sfi;
960 stackframeinfo_t tmpsfi;
963 classloader_t *syscl;
966 if (opt_DebugStackTrace)
967 log_println("[stacktrace_first_nonsystem_classloader]");
970 // Get the stackframeinfo of the current thread.
971 sfi = threads_get_current_stackframeinfo();
973 // Get the system class class loader.
974 syscl = java_lang_ClassLoader::invoke_getSystemClassLoader();
976 // Iterate over the whole stack.
977 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
978 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
979 stacktrace_stackframeinfo_next(&tmpsfi)) {
982 cl = class_get_classloader(m->clazz);
987 // XXX if a method in a class in a trusted loader is in a
988 // doPrivileged, return NULL (or break) here.
990 if (!is_ancestor_of(cl, syscl))
996 #endif /* defined(ENABLE_JAVASE) */
999 /* stacktrace_getClassContext **************************************************
1001 Creates a Class context array.
1004 the array of java.lang.Class objects, or
1005 NULL if an exception has been thrown
1007 *******************************************************************************/
1009 java_handle_objectarray_t *stacktrace_getClassContext(void)
1011 stackframeinfo_t *sfi;
1012 stackframeinfo_t tmpsfi;
1017 CYCLES_STATS_DECLARE_AND_START
1019 #if !defined(NDEBUG)
1020 if (opt_DebugStackTrace)
1021 log_println("[stacktrace_getClassContext]");
1024 sfi = threads_get_current_stackframeinfo();
1026 /* Get the depth of the current stack. */
1028 depth = stacktrace_depth(sfi);
1030 /* The first stackframe corresponds to the method whose
1031 implementation calls this native function. We remove that
1035 stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1036 stacktrace_stackframeinfo_next(&tmpsfi);
1038 /* Allocate the Class array. */
1040 ClassArray ca(depth);
1043 CYCLES_STATS_END(stacktrace_getClassContext);
1048 /* Fill the Class array from the stacktrace list. */
1049 /* Iterate over the whole stack. */
1054 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1055 stacktrace_stackframeinfo_next(&tmpsfi)) {
1056 /* Get methodinfo. */
1060 /* Skip builtin methods. */
1062 if (m->flags & ACC_METHOD_BUILTIN)
1065 /* Store the class in the array. */
1067 ca.set_element(i, m->clazz);
1074 CYCLES_STATS_END(stacktrace_getClassContext)
1076 return ca.get_handle();
1080 /* stacktrace_getCurrentClass **************************************************
1082 Find the current class by walking the stack trace.
1084 Quote from the JNI documentation:
1086 In the Java 2 Platform, FindClass locates the class loader
1087 associated with the current native method. If the native code
1088 belongs to a system class, no class loader will be
1089 involved. Otherwise, the proper class loader will be invoked to
1090 load and link the named class. When FindClass is called through the
1091 Invocation Interface, there is no current native method or its
1092 associated class loader. In that case, the result of
1093 ClassLoader.getBaseClassLoader is used."
1095 *******************************************************************************/
1097 #if defined(ENABLE_JAVASE)
1098 classinfo *stacktrace_get_current_class(void)
1100 stackframeinfo_t *sfi;
1101 stackframeinfo_t tmpsfi;
1104 CYCLES_STATS_DECLARE_AND_START;
1106 #if !defined(NDEBUG)
1107 if (opt_DebugStackTrace)
1108 log_println("[stacktrace_get_current_class]");
1111 /* Get the stackframeinfo of the current thread. */
1113 sfi = threads_get_current_stackframeinfo();
1115 /* If the stackframeinfo is NULL then FindClass is called through
1116 the Invocation Interface and we return NULL */
1119 CYCLES_STATS_END(stacktrace_getCurrentClass);
1124 /* Iterate over the whole stack. */
1126 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1127 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1128 stacktrace_stackframeinfo_next(&tmpsfi)) {
1129 /* Get the methodinfo. */
1133 if (m->clazz == class_java_security_PrivilegedAction) {
1134 CYCLES_STATS_END(stacktrace_getCurrentClass);
1139 if (m->clazz != NULL) {
1140 CYCLES_STATS_END(stacktrace_getCurrentClass);
1146 /* No Java method found on the stack. */
1148 CYCLES_STATS_END(stacktrace_getCurrentClass);
1152 #endif /* ENABLE_JAVASE */
1155 /* stacktrace_get_stack ********************************************************
1157 Create a 2-dimensional array for java.security.VMAccessControler.
1161 NULL if an exception has been thrown
1163 *******************************************************************************/
1165 #if defined(ENABLE_JAVASE) && defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
1166 java_handle_objectarray_t *stacktrace_get_stack(void)
1168 stackframeinfo_t *sfi;
1169 stackframeinfo_t tmpsfi;
1172 java_handle_t *string;
1175 CYCLES_STATS_DECLARE_AND_START
1177 #if !defined(NDEBUG)
1178 if (opt_DebugStackTrace)
1179 log_println("[stacktrace_get_stack]");
1182 /* Get the stackframeinfo of the current thread. */
1184 sfi = threads_get_current_stackframeinfo();
1186 /* Get the depth of the current stack. */
1188 depth = stacktrace_depth(sfi);
1193 /* Allocate the required arrays. */
1195 ObjectArray oa(2, arrayclass_java_lang_Object);
1196 ClassArray classes(depth);
1197 ObjectArray methodnames(depth, class_java_lang_String);
1202 if (classes.is_null())
1205 if (methodnames.is_null())
1208 /* Set up the 2-dimensional array. */
1210 oa.set_element(0, (java_handle_t *) classes.get_handle());
1211 oa.set_element(1, (java_handle_t *) methodnames.get_handle());
1213 /* Iterate over the whole stack. */
1214 /* TODO We should use a critical section here to speed things
1219 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1220 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1221 stacktrace_stackframeinfo_next(&tmpsfi)) {
1222 /* Get the methodinfo. */
1226 /* Skip builtin methods. */
1228 if (m->flags & ACC_METHOD_BUILTIN)
1231 /* Store the class in the array. */
1233 classes.set_element(i, m->clazz);
1235 /* Store the name in the array. */
1237 string = javastring_new(m->name);
1242 methodnames.set_element(i, string);
1247 CYCLES_STATS_END(stacktrace_get_stack)
1249 return oa.get_handle();
1252 CYCLES_STATS_END(stacktrace_get_stack)
1259 /* stacktrace_print_entry ****************************************************
1261 Print line for a stacktrace entry.
1264 m ............ methodinfo of the entry
1265 linenumber ... linenumber of the entry
1267 *******************************************************************************/
1269 static void stacktrace_print_entry(methodinfo *m, int32_t linenumber)
1277 if (m->flags & ACC_METHOD_BUILTIN)
1280 utf_display_printable_ascii_classname(m->clazz->name);
1283 utf_display_printable_ascii(m->name);
1284 utf_display_printable_ascii(m->descriptor);
1286 if (m->flags & ACC_NATIVE) {
1287 puts("(Native Method)");
1290 if (m->flags & ACC_METHOD_BUILTIN) {
1295 utf_display_printable_ascii(m->clazz->sourcefile);
1296 printf(":%d)\n", linenumber);
1304 /* stacktrace_print ************************************************************
1306 Print the given stacktrace with CACAO intern methods only (no Java
1309 This method is used by stacktrace_dump_trace and
1310 builtin_trace_exception.
1313 st ... stacktrace to print
1315 *******************************************************************************/
1317 void stacktrace_print(stacktrace_t *st)
1319 stacktrace_entry_t *ste;
1324 ste = &(st->entries[0]);
1326 for (i = 0; i < st->length; i++, ste++) {
1329 /* Get the line number. */
1331 linenumber = ste->code->linenumbertable->find(&m, ste->pc);
1333 stacktrace_print_entry(m, linenumber);
1338 /* stacktrace_print_current ****************************************************
1340 Print the current stacktrace of the current thread.
1342 NOTE: This function prints all frames of the stacktrace and does
1343 not skip frames like stacktrace_get.
1345 *******************************************************************************/
1347 void stacktrace_print_current(void)
1349 stackframeinfo_t *sfi;
1350 stackframeinfo_t tmpsfi;
1355 sfi = threads_get_current_stackframeinfo();
1358 puts("\t<<No stacktrace available>>");
1363 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1364 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1365 stacktrace_stackframeinfo_next(&tmpsfi)) {
1366 /* Get the methodinfo. */
1371 // Get the line number.
1372 linenumber = code->linenumbertable->find(&m, tmpsfi.xpc);
1374 stacktrace_print_entry(m, linenumber);
1380 * Creates a stacktrace for the given thread.
1382 * @param t Given thread.
1383 * @return Current stacktrace of the given thread.
1385 * XXX: Creation of the stacktrace starts at the most recent
1386 * stackframeinfo block. If the thread is not inside the native
1387 * world, the created stacktrace is not complete!
1389 #if defined(ENABLE_THREADS)
1390 stacktrace_t* stacktrace_get_of_thread(threadobject* t)
1392 stackframeinfo_t* sfi;
1393 java_handle_bytearray_t* stba;
1396 sfi = t->_stackframeinfo;
1397 stba = stacktrace_get(sfi);
1404 st = (stacktrace_t*) ba.get_raw_data_ptr();
1411 /* stacktrace_print_of_thread **************************************************
1413 Print the current stacktrace of the given thread. It will only work
1414 for suspended threads.
1419 *******************************************************************************/
1421 #if defined(ENABLE_THREADS)
1422 void stacktrace_print_of_thread(threadobject *t)
1424 stackframeinfo_t *sfi;
1425 stackframeinfo_t tmpsfi;
1430 /* Build a stacktrace for the passed thread. */
1432 sfi = t->_stackframeinfo;
1434 if (!t->suspended || sfi == NULL) {
1435 puts("\t<<No stacktrace available>>");
1440 for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1441 stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1442 stacktrace_stackframeinfo_next(&tmpsfi)) {
1443 /* Get the methodinfo. */
1448 // Get the line number.
1449 linenumber = code->linenumbertable->find(&m, tmpsfi.xpc);
1451 stacktrace_print_entry(m, linenumber);
1457 /* stacktrace_print_exception **************************************************
1459 Print the stacktrace of a given exception (more or less a wrapper
1460 to stacktrace_print).
1463 h ... handle of exception to print
1465 *******************************************************************************/
1467 void stacktrace_print_exception(java_handle_t *h)
1472 java_lang_Throwable t(h);
1474 /* now print the stacktrace */
1476 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
1478 java_lang_VMThrowable vmt(t.get_vmState());
1479 ByteArray backtrace(vmt.get_vmdata());
1481 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) || defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
1483 ByteArray backtrace(t.get_backtrace());
1486 # error unknown classpath configuration
1491 assert(backtrace.is_non_null());
1493 /* We need a critical section here as we use the byte-array data
1494 pointer directly. */
1496 LLNI_CRITICAL_START;
1498 stacktrace_t* st = (stacktrace_t*) backtrace.get_raw_data_ptr();
1500 stacktrace_print(st);
1506 #if defined(ENABLE_CYCLES_STATS)
1507 void stacktrace_print_cycles_stats(FILE *file)
1509 CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead, file);
1510 CYCLES_STATS_PRINT(stacktrace_get, file);
1511 CYCLES_STATS_PRINT(stacktrace_getClassContext , file);
1512 CYCLES_STATS_PRINT(stacktrace_getCurrentClass , file);
1513 CYCLES_STATS_PRINT(stacktrace_get_stack, file);
1521 * These are local overrides for various environment variables in Emacs.
1522 * Please do not remove this and leave it at the end of the file, where
1523 * Emacs will automagically detect them.
1524 * ---------------------------------------------------------------------
1527 * indent-tabs-mode: t
1531 * vim:noexpandtab:sw=4:ts=4: