* src/cacaoh/dummy.c: Removed asm_criticalsections and
[cacao.git] / src / vm / jit / stacktrace.c
1 /* src/vm/jit/stacktrace.c - machine independent stacktrace system
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
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.
12
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.
17
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
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <assert.h>
29 #include <stdint.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "vm/types.h"
34
35 #include "md.h"
36
37 #include "mm/gc-common.h"
38 #include "mm/memory.h"
39
40 #include "vm/jit/stacktrace.h"
41
42 #include "vm/global.h"                   /* required here for native includes */
43 #include "native/jni.h"
44 #include "native/llni.h"
45
46 #include "native/include/java_lang_Object.h"
47 #include "native/include/java_lang_Throwable.h"
48
49 #if defined(WITH_CLASSPATH_GNU)
50 # include "native/include/gnu_classpath_Pointer.h"
51 # include "native/include/java_lang_VMThrowable.h"
52 #endif
53
54 #include "threads/thread.h"
55
56 #include "toolbox/logging.h"
57
58 #include "vm/array.h"
59 #include "vm/builtin.h"
60 #include "vm/cycles-stats.h"
61 #include "vm/exceptions.h"
62 #include "vm/stringlocal.h"
63 #include "vm/vm.h"
64
65 #include "vm/jit/asmpart.h"
66 #include "vm/jit/codegen-common.h"
67 #include "vm/jit/linenumbertable.h"
68 #include "vm/jit/methodheader.h"
69 #include "vm/jit/methodtree.h"
70
71 #include "vmcore/class.h"
72 #include "vmcore/loader.h"
73 #include "vmcore/method.h"
74 #include "vmcore/options.h"
75
76
77 /* global variables ***********************************************************/
78
79 CYCLES_STATS_DECLARE(stacktrace_overhead        , 100, 1)
80 CYCLES_STATS_DECLARE(stacktrace_get,              40,  5000)
81 CYCLES_STATS_DECLARE(stacktrace_getClassContext , 40,  5000)
82 CYCLES_STATS_DECLARE(stacktrace_getCurrentClass , 40,  5000)
83 CYCLES_STATS_DECLARE(stacktrace_get_stack       , 40,  10000)
84
85
86 /* stacktrace_stackframeinfo_add ***********************************************
87
88    Fills a stackframe info structure with the given or calculated
89    values and adds it to the chain.
90
91 *******************************************************************************/
92
93 void stacktrace_stackframeinfo_add(stackframeinfo_t *sfi, u1 *pv, u1 *sp, u1 *ra, u1 *xpc)
94 {
95         stackframeinfo_t *currentsfi;
96         codeinfo         *code;
97 #if defined(ENABLE_JIT)
98         s4                 framesize;
99 #endif
100
101         /* Get current stackframe info. */
102
103         currentsfi = threads_get_current_stackframeinfo();
104
105         /* sometimes we don't have pv handy (e.g. in asmpart.S:
106        L_asm_call_jit_compiler_exception or in the interpreter). */
107
108         if (pv == NULL) {
109 #if defined(ENABLE_INTRP)
110                 if (opt_intrp)
111                         pv = methodtree_find(ra);
112                 else
113 #endif
114                         {
115 #if defined(ENABLE_JIT)
116 # if defined(__SPARC_64__)
117                                 pv = md_get_pv_from_stackframe(sp);
118 # else
119                                 pv = md_codegen_get_pv_from_pc(ra);
120 # endif
121 #endif
122                         }
123         }
124
125         /* Get codeinfo pointer for the parent Java method. */
126
127         code = code_get_codeinfo_for_pv(pv);
128
129         /* XXX */
130         /*      assert(m != NULL); */
131
132 #if defined(ENABLE_JIT)
133 # if defined(ENABLE_INTRP)
134         /* When using the interpreter, we pass RA to the function. */
135
136         if (!opt_intrp) {
137 # endif
138 # if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__M68K__)
139                 /* On i386 and x86_64 we always have to get the return address
140                    from the stack. */
141                 /* m68k has return address on stack always */
142                 /* On S390 we use REG_RA as REG_ITMP3, so we have always to get
143                    the RA from stack. */
144
145                 framesize = *((u4 *) (pv + FrameSize));
146
147                 ra = md_stacktrace_get_returnaddress(sp, framesize);
148 # else
149                 /* If the method is a non-leaf function, we need to get the
150                    return address from the stack.  For leaf functions the
151                    return address is set correctly.  This makes the assembler
152                    and the signal handler code simpler.  The code is NULL is
153                    the asm_vm_call_method special case. */
154
155                 if ((code == NULL) || !code_is_leafmethod(code)) {
156                         framesize = *((u4 *) (pv + FrameSize));
157
158                         ra = md_stacktrace_get_returnaddress(sp, framesize);
159                 }
160 # endif
161 # if defined(ENABLE_INTRP)
162         }
163 # endif
164 #endif
165
166         /* Calculate XPC when not given.  The XPC is then the return
167            address of the current method minus 1 because the RA points to
168            the instruction after the call instruction.  This is required
169            e.g. for method stubs. */
170
171         if (xpc == NULL) {
172                 xpc = (void *) (((intptr_t) ra) - 1);
173         }
174
175         /* Fill new stackframeinfo structure. */
176
177         sfi->prev = currentsfi;
178         sfi->code = code;
179         sfi->pv   = pv;
180         sfi->sp   = sp;
181         sfi->ra   = ra;
182         sfi->xpc  = xpc;
183
184 #if !defined(NDEBUG)
185         if (opt_DebugStackFrameInfo) {
186                 log_start();
187                 log_print("[stackframeinfo add   : sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
188                                   sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
189                 method_print(sfi->code->m);
190                 log_print("]");
191                 log_finish();
192         }
193 #endif
194
195         /* Store new stackframeinfo pointer. */
196
197         threads_set_current_stackframeinfo(sfi);
198
199         /* set the native world flag for the current thread */
200         /* ATTENTION: This flag tells the GC how to treat this thread in case of
201            a collection. Set this flag _after_ a valid stackframe info was set. */
202
203         THREAD_NATIVEWORLD_ENTER;
204 }
205
206
207 /* stacktrace_stackframeinfo_remove ********************************************
208
209    Remove the given stackframeinfo from the chain in the current
210    thread.
211
212 *******************************************************************************/
213
214 void stacktrace_stackframeinfo_remove(stackframeinfo_t *sfi)
215 {
216         /* Clear the native world flag for the current thread. */
217         /* ATTENTION: Clear this flag _before_ removing the stackframe info. */
218
219         THREAD_NATIVEWORLD_EXIT;
220
221 #if !defined(NDEBUG)
222         if (opt_DebugStackFrameInfo) {
223                 log_start();
224                 log_print("[stackframeinfo remove: sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
225                                   sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
226                 method_print(sfi->code->m);
227                 log_print("]");
228                 log_finish();
229         }
230 #endif
231
232         /* Set previous stackframe info. */
233
234         threads_set_current_stackframeinfo(sfi->prev);
235 }
236
237
238 /* stacktrace_stackframeinfo_fill **********************************************
239
240    Fill the temporary stackframeinfo structure with the values given
241    in sfi.
242
243    IN:
244        tmpsfi ... temporary stackframeinfo
245        sfi ...... stackframeinfo to be used in the next iteration
246
247 *******************************************************************************/
248
249 static inline void stacktrace_stackframeinfo_fill(stackframeinfo_t *tmpsfi, stackframeinfo_t *sfi)
250 {
251         /* Sanity checks. */
252
253         assert(tmpsfi != NULL);
254         assert(sfi != NULL);
255
256         /* Fill the temporary stackframeinfo. */
257
258         tmpsfi->code = sfi->code;
259         tmpsfi->pv   = sfi->pv;
260         tmpsfi->sp   = sfi->sp;
261         tmpsfi->ra   = sfi->ra;
262         tmpsfi->xpc  = sfi->xpc;
263
264         /* Set the previous stackframe info of the temporary one to the
265            next in the chain. */
266
267         tmpsfi->prev = sfi->prev;
268
269 #if !defined(NDEBUG)
270         if (opt_DebugStackTrace)
271                 log_println("[stacktrace fill]");
272 #endif
273 }
274
275
276 /* stacktrace_stackframeinfo_next **********************************************
277
278    Walk the stack (or the stackframeinfo-chain) to the next method and
279    return the new stackframe values in the temporary stackframeinfo
280    passed.
281
282    ATTENTION: This function does NOT skip builtin methods!
283
284    IN:
285        tmpsfi ... temporary stackframeinfo of current method
286
287 *******************************************************************************/
288
289 static inline void stacktrace_stackframeinfo_next(stackframeinfo_t *tmpsfi)
290 {
291         codeinfo         *code;
292         void             *pv;
293         void             *sp;
294         void             *ra;
295         void             *xpc;
296         uint32_t          framesize;
297         stackframeinfo_t *prevsfi;
298
299         /* Sanity check. */
300
301         assert(tmpsfi != NULL);
302
303         /* Get values from the stackframeinfo. */
304
305         code = tmpsfi->code;
306         pv   = tmpsfi->pv;
307         sp   = tmpsfi->sp;
308         ra   = tmpsfi->ra;
309         xpc  = tmpsfi->xpc;
310  
311         /* Get the current stack frame size. */
312
313         framesize = *((uint32_t *) (((intptr_t) pv) + FrameSize));
314
315         /* Get the RA of the current stack frame (RA to the parent Java
316            method) if the current method is a non-leaf method.  Otherwise
317            the value in the stackframeinfo is correct (from the signal
318            handler). */
319
320 #if defined(ENABLE_JIT)
321 # if defined(ENABLE_INTRP)
322         if (opt_intrp)
323                 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
324         else
325 # endif
326                 {
327                         if (!code_is_leafmethod(code))
328                                 ra = md_stacktrace_get_returnaddress(sp, framesize);
329                 }
330 #else
331         ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
332 #endif
333
334         /* Get the PV for the parent Java method. */
335
336 #if defined(ENABLE_INTRP)
337         if (opt_intrp)
338                 pv = methodtree_find(ra);
339         else
340 #endif
341                 {
342 #if defined(ENABLE_JIT)
343 # if defined(__SPARC_64__)
344                         sp = md_get_framepointer(sp);
345                         pv = md_get_pv_from_stackframe(sp);
346 # else
347                         pv = md_codegen_get_pv_from_pc(ra);
348 # endif
349 #endif
350                 }
351
352         /* Get the codeinfo pointer for the parent Java method. */
353
354         code = code_get_codeinfo_for_pv(pv);
355
356         /* Calculate the SP for the parent Java method. */
357
358 #if defined(ENABLE_INTRP)
359         if (opt_intrp)
360                 sp = *(u1 **) (sp - framesize);
361         else
362 #endif
363                 {
364 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
365                         sp = (void *) (((intptr_t) sp) + framesize + SIZEOF_VOID_P);
366 #elif defined(__SPARC_64__)
367                         /* already has the new sp */
368 #else
369                         sp = (void *) (((intptr_t) sp) + framesize);
370 #endif
371                 }
372
373         /* If the new codeinfo pointer is NULL we reached a
374            asm_vm_call_method function.  In this case we get the next
375            values from the previous stackframeinfo in the chain.
376            Otherwise the new values have been calculated before. */
377
378         if (code == NULL) {
379                 prevsfi = tmpsfi->prev;
380
381                 /* If the previous stackframeinfo in the chain is NULL we
382                    reached the top of the stacktrace.  We set code and prev to
383                    NULL to mark the end, which is checked in
384                    stacktrace_stackframeinfo_end_check. */
385
386                 if (prevsfi == NULL) {
387                         tmpsfi->code = NULL;
388                         tmpsfi->prev = NULL;
389                         return;
390                 }
391
392                 /* Fill the temporary stackframeinfo with the new values. */
393
394                 stacktrace_stackframeinfo_fill(tmpsfi, prevsfi);
395         }
396         else {
397                 /* Store the new values in the stackframeinfo.  NOTE: We
398                    subtract 1 from the RA to get the XPC, because the RA
399                    points to the instruction after the call instruction. */
400
401                 tmpsfi->code = code;
402                 tmpsfi->pv   = pv;
403                 tmpsfi->sp   = sp;
404                 tmpsfi->ra   = ra;
405                 tmpsfi->xpc  = (void *) (((intptr_t) ra) - 1);
406         }
407
408 #if !defined(NDEBUG)
409         /* Print current method information. */
410
411         if (opt_DebugStackTrace) {
412                 log_start();
413                 log_print("[stacktrace: method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
414                                   tmpsfi->code->m, tmpsfi->pv, tmpsfi->sp, tmpsfi->ra,
415                                   tmpsfi->xpc);
416                 method_print(tmpsfi->code->m);
417                 log_print("]");
418                 log_finish();
419         }
420 #endif
421 }
422
423
424 /* stacktrace_stackframeinfo_end_check *****************************************
425
426    Check if we reached the end of the stacktrace.
427
428    IN:
429        tmpsfi ... temporary stackframeinfo of current method
430
431    RETURN:
432        true .... the end is reached
433            false ... the end is not reached
434
435 *******************************************************************************/
436
437 static inline bool stacktrace_stackframeinfo_end_check(stackframeinfo_t *tmpsfi)
438 {
439         /* Sanity check. */
440
441         assert(tmpsfi != NULL);
442
443         if ((tmpsfi->code == NULL) && (tmpsfi->prev == NULL)) {
444 #if !defined(NDEBUG)
445                 if (opt_DebugStackTrace)
446                         log_println("[stacktrace stop]");
447 #endif
448
449                 return true;
450         }
451
452         return false;
453 }
454
455
456 /* stacktrace_depth ************************************************************
457
458    Calculates and returns the depth of the current stacktrace.
459
460    IN:
461        sfi ... stackframeinfo where to start the stacktrace
462
463    RETURN:
464        depth of the stacktrace
465
466 *******************************************************************************/
467
468 static int stacktrace_depth(stackframeinfo_t *sfi)
469 {
470         stackframeinfo_t  tmpsfi;
471         int               depth;
472         methodinfo       *m;
473
474 #if !defined(NDEBUG)
475         if (opt_DebugStackTrace)
476                 log_println("[stacktrace_depth]");
477 #endif
478
479         /* XXX This is not correct, but a workaround for threads-dump for
480            now. */
481 /*      assert(sfi != NULL); */
482         if (sfi == NULL)
483                 return 0;
484
485         /* Iterate over all stackframes. */
486
487         depth = 0;
488
489         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
490                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
491                  stacktrace_stackframeinfo_next(&tmpsfi)) {
492                 /* Get methodinfo. */
493
494                 m = tmpsfi.code->m;
495
496                 /* Skip builtin methods. */
497
498                 if (m->flags & ACC_METHOD_BUILTIN)
499                         continue;
500
501                 depth++;
502         }
503
504         return depth;
505 }
506
507
508 /* stacktrace_get **************************************************************
509
510    Builds and returns a stacktrace starting from the given stackframe
511    info and returns the stacktrace structure wrapped in a Java
512    byte-array to not confuse the GC.
513
514    IN:
515        sfi ... stackframe info to start stacktrace from
516
517    RETURN:
518        stacktrace as Java byte-array
519
520 *******************************************************************************/
521
522 java_handle_bytearray_t *stacktrace_get(stackframeinfo_t *sfi)
523 {
524         stackframeinfo_t         tmpsfi;
525         int                      depth;
526         java_handle_bytearray_t *ba;
527         int32_t                  ba_size;
528         stacktrace_t            *st;
529         stacktrace_entry_t      *ste;
530         methodinfo              *m;
531         bool                     skip_fillInStackTrace;
532         bool                     skip_init;
533
534         CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
535
536 #if !defined(NDEBUG)
537         if (opt_DebugStackTrace)
538                 log_println("[stacktrace_get]");
539 #endif
540
541         skip_fillInStackTrace = true;
542         skip_init             = true;
543
544         depth = stacktrace_depth(sfi);
545
546         if (depth == 0)
547                 return NULL;
548
549         /* Allocate memory from the GC heap and copy the stacktrace
550            buffer. */
551         /* ATTENTION: Use a Java byte-array for this to not confuse the
552            GC. */
553         /* FIXME: We waste some memory here as we skip some entries
554            later. */
555
556         ba_size = sizeof(stacktrace_t) + sizeof(stacktrace_entry_t) * depth;
557
558         ba = builtin_newarray_byte(ba_size);
559
560         if (ba == NULL)
561                 goto return_NULL;
562
563         /* Get a stacktrace entry pointer. */
564         /* ATTENTION: We need a critical section here because we use the
565            byte-array data pointer directly. */
566
567         LLNI_CRITICAL_START;
568
569         st = (stacktrace_t *) LLNI_array_data(ba);
570
571         ste = st->entries;
572
573         /* Iterate over the whole stack. */
574
575         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
576                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
577                  stacktrace_stackframeinfo_next(&tmpsfi)) {
578                 /* Get the methodinfo. */
579
580                 m = tmpsfi.code->m;
581
582                 /* Skip builtin methods. */
583
584                 if (m->flags & ACC_METHOD_BUILTIN)
585                         continue;
586
587                 /* This logic is taken from
588                    hotspot/src/share/vm/classfile/javaClasses.cpp
589                    (java_lang_Throwable::fill_in_stack_trace). */
590
591                 if (skip_fillInStackTrace == true) {
592                         /* Check "fillInStackTrace" only once, so we negate the
593                            flag after the first time check. */
594
595 #if defined(WITH_CLASSPATH_GNU)
596                         /* For GNU Classpath we also need to skip
597                            VMThrowable.fillInStackTrace(). */
598
599                         if ((m->clazz == class_java_lang_VMThrowable) &&
600                                 (m->name  == utf_fillInStackTrace))
601                                 continue;
602 #endif
603
604                         skip_fillInStackTrace = false;
605
606                         if (m->name == utf_fillInStackTrace)
607                                 continue;
608                 }
609
610                 /* Skip <init> methods of the exceptions klass.  If there is
611                    <init> methods that belongs to a superclass of the
612                    exception we are going to skipping them in stack trace. */
613
614                 if (skip_init == true) {
615                         if ((m->name == utf_init) &&
616                                 (class_issubclass(m->clazz, class_java_lang_Throwable))) {
617                                 continue;
618                         }
619                         else {
620                                 /* If no "Throwable.init()" method found, we stop
621                                    checking it next time. */
622
623                                 skip_init = false;
624                         }
625                 }
626
627                 /* Store the stacktrace entry and increment the pointer. */
628
629                 ste->code = tmpsfi.code;
630                 ste->pc   = tmpsfi.xpc;
631
632                 ste++;
633         }
634
635         /* Store the number of entries in the stacktrace structure. */
636
637         st->length = ste - st->entries;
638
639         LLNI_CRITICAL_END;
640
641         /* release dump memory */
642
643 /*      dump_release(dumpsize); */
644
645         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
646                                                                    stacktrace_overhead)
647         return ba;
648
649 return_NULL:
650 /*      dump_release(dumpsize); */
651
652         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
653                                                                    stacktrace_overhead)
654
655         return NULL;
656 }
657
658
659 /* stacktrace_get_current ******************************************************
660
661    Builds and returns a stacktrace from the current thread and returns
662    the stacktrace structure wrapped in a Java byte-array to not
663    confuse the GC.
664
665    RETURN:
666        stacktrace as Java byte-array
667
668 *******************************************************************************/
669
670 java_handle_bytearray_t *stacktrace_get_current(void)
671 {
672         stackframeinfo_t        *sfi;
673         java_handle_bytearray_t *ba;
674
675         sfi = threads_get_current_stackframeinfo();
676         ba  = stacktrace_get(sfi);
677
678         return ba;
679 }
680
681
682 /* stacktrace_get_caller_class *************************************************
683
684    Get the class on the stack at the given depth.  This function skips
685    various special classes or methods.
686
687    ARGUMENTS:
688        depth ... depth to get caller class of
689
690    RETURN:
691        caller class
692
693 *******************************************************************************/
694
695 #if defined(ENABLE_JAVASE)
696 classinfo *stacktrace_get_caller_class(int depth)
697 {
698         stackframeinfo_t *sfi;
699         stackframeinfo_t  tmpsfi;
700         methodinfo       *m;
701         classinfo        *c;
702         int               i;
703
704 #if !defined(NDEBUG)
705         if (opt_DebugStackTrace)
706                 log_println("[stacktrace_get_caller_class]");
707 #endif
708
709         /* Get the stackframeinfo of the current thread. */
710
711         sfi = threads_get_current_stackframeinfo();
712
713         /* Iterate over the whole stack until we reached the requested
714            depth. */
715
716         i = 0;
717
718         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
719                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
720                  stacktrace_stackframeinfo_next(&tmpsfi)) {
721
722                 m = tmpsfi.code->m;
723                 c = m->clazz;
724
725                 /* Skip builtin methods. */
726
727                 if (m->flags & ACC_METHOD_BUILTIN)
728                         continue;
729
730 #if defined(WITH_CLASSPATH_SUN)
731                 /* NOTE: See hotspot/src/share/vm/runtime/vframe.cpp
732                    (vframeStreamCommon::security_get_caller_frame). */
733
734                 /* This is java.lang.reflect.Method.invoke(), skip it. */
735
736                 if (m == method_java_lang_reflect_Method_invoke)
737                         continue;
738
739                 /* This is an auxiliary frame, skip it. */
740
741                 if (class_issubclass(c, class_sun_reflect_MagicAccessorImpl))
742                         continue;
743 #endif
744
745                 /* We reached the requested depth. */
746
747                 if (i >= depth)
748                         return c;
749
750                 i++;
751         }
752
753         return NULL;
754 }
755 #endif
756
757
758 /* stacktrace_first_nonnull_classloader ****************************************
759
760    Returns the first non-null (user-defined) classloader on the stack.
761    If none is found NULL is returned.
762
763    RETURN:
764        classloader
765
766 *******************************************************************************/
767
768 classloader_t *stacktrace_first_nonnull_classloader(void)
769 {
770         stackframeinfo_t *sfi;
771         stackframeinfo_t  tmpsfi;
772         methodinfo       *m;
773         classloader_t    *cl;
774
775 #if !defined(NDEBUG)
776         if (opt_DebugStackTrace)
777                 log_println("[stacktrace_first_nonnull_classloader]");
778 #endif
779
780         /* Get the stackframeinfo of the current thread. */
781
782         sfi = threads_get_current_stackframeinfo();
783
784         /* Iterate over the whole stack. */
785
786         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
787                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
788                  stacktrace_stackframeinfo_next(&tmpsfi)) {
789
790                 m  = tmpsfi.code->m;
791                 cl = class_get_classloader(m->clazz);
792
793                 if (cl != NULL)
794                         return cl;
795         }
796
797         return NULL;
798 }
799
800
801 /* stacktrace_getClassContext **************************************************
802
803    Creates a Class context array.
804
805    RETURN VALUE:
806       the array of java.lang.Class objects, or
807           NULL if an exception has been thrown
808
809 *******************************************************************************/
810
811 java_handle_objectarray_t *stacktrace_getClassContext(void)
812 {
813         stackframeinfo_t           *sfi;
814         stackframeinfo_t            tmpsfi;
815         int                         depth;
816         java_handle_objectarray_t  *oa;
817         java_object_t             **data;
818         int                         i;
819         methodinfo                 *m;
820
821         CYCLES_STATS_DECLARE_AND_START
822
823 #if !defined(NDEBUG)
824         if (opt_DebugStackTrace)
825                 log_println("[stacktrace_getClassContext]");
826 #endif
827
828         sfi = threads_get_current_stackframeinfo();
829
830         /* Get the depth of the current stack. */
831
832         depth = stacktrace_depth(sfi);
833
834         /* The first stackframe corresponds to the method whose
835            implementation calls this native function.  We remove that
836            entry. */
837
838         depth--;
839         stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
840         stacktrace_stackframeinfo_next(&tmpsfi);
841
842         /* Allocate the Class array. */
843
844         oa = builtin_anewarray(depth, class_java_lang_Class);
845
846         if (oa == NULL) {
847                 CYCLES_STATS_END(stacktrace_getClassContext);
848
849                 return NULL;
850         }
851
852         /* Fill the Class array from the stacktrace list. */
853
854         LLNI_CRITICAL_START;
855
856         data = LLNI_array_data(oa);
857
858         /* Iterate over the whole stack. */
859
860         i = 0;
861
862         for (;
863                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
864                  stacktrace_stackframeinfo_next(&tmpsfi)) {
865                 /* Get methodinfo. */
866
867                 m = tmpsfi.code->m;
868
869                 /* Skip builtin methods. */
870
871                 if (m->flags & ACC_METHOD_BUILTIN)
872                         continue;
873
874                 /* Store the class in the array. */
875
876                 data[i] = (java_object_t *) m->clazz;
877
878                 i++;
879         }
880
881         LLNI_CRITICAL_END;
882
883         CYCLES_STATS_END(stacktrace_getClassContext)
884
885         return oa;
886 }
887
888
889 /* stacktrace_getCurrentClass **************************************************
890
891    Find the current class by walking the stack trace.
892
893    Quote from the JNI documentation:
894          
895    In the Java 2 Platform, FindClass locates the class loader
896    associated with the current native method.  If the native code
897    belongs to a system class, no class loader will be
898    involved. Otherwise, the proper class loader will be invoked to
899    load and link the named class. When FindClass is called through the
900    Invocation Interface, there is no current native method or its
901    associated class loader. In that case, the result of
902    ClassLoader.getBaseClassLoader is used."
903
904 *******************************************************************************/
905
906 #if defined(ENABLE_JAVASE)
907 classinfo *stacktrace_get_current_class(void)
908 {
909         stackframeinfo_t *sfi;
910         stackframeinfo_t  tmpsfi;
911         methodinfo       *m;
912
913         CYCLES_STATS_DECLARE_AND_START;
914
915 #if !defined(NDEBUG)
916         if (opt_DebugStackTrace)
917                 log_println("[stacktrace_get_current_class]");
918 #endif
919
920         /* Get the stackframeinfo of the current thread. */
921
922         sfi = threads_get_current_stackframeinfo();
923
924         /* If the stackframeinfo is NULL then FindClass is called through
925            the Invocation Interface and we return NULL */
926
927         if (sfi == NULL) {
928                 CYCLES_STATS_END(stacktrace_getCurrentClass);
929
930                 return NULL;
931         }
932
933         /* Iterate over the whole stack. */
934
935         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
936                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
937                  stacktrace_stackframeinfo_next(&tmpsfi)) {
938                 /* Get the methodinfo. */
939
940                 m = tmpsfi.code->m;
941
942                 if (m->clazz == class_java_security_PrivilegedAction) {
943                         CYCLES_STATS_END(stacktrace_getCurrentClass);
944
945                         return NULL;
946                 }
947
948                 if (m->clazz != NULL) {
949                         CYCLES_STATS_END(stacktrace_getCurrentClass);
950
951                         return m->clazz;
952                 }
953         }
954
955         /* No Java method found on the stack. */
956
957         CYCLES_STATS_END(stacktrace_getCurrentClass);
958
959         return NULL;
960 }
961 #endif /* ENABLE_JAVASE */
962
963
964 /* stacktrace_get_stack ********************************************************
965
966    Create a 2-dimensional array for java.security.VMAccessControler.
967
968    RETURN VALUE:
969       the arrary, or
970          NULL if an exception has been thrown
971
972 *******************************************************************************/
973
974 #if defined(ENABLE_JAVASE) && defined(WITH_CLASSPATH_GNU)
975 java_handle_objectarray_t *stacktrace_get_stack(void)
976 {
977         stackframeinfo_t          *sfi;
978         stackframeinfo_t           tmpsfi;
979         int                        depth;
980         java_handle_objectarray_t *oa;
981         java_handle_objectarray_t *classes;
982         java_handle_objectarray_t *methodnames;
983         methodinfo                *m;
984         java_handle_t             *string;
985         int                        i;
986
987         CYCLES_STATS_DECLARE_AND_START
988
989 #if !defined(NDEBUG)
990         if (opt_DebugStackTrace)
991                 log_println("[stacktrace_get_stack]");
992 #endif
993
994         /* Get the stackframeinfo of the current thread. */
995
996         sfi = threads_get_current_stackframeinfo();
997
998         /* Get the depth of the current stack. */
999
1000         depth = stacktrace_depth(sfi);
1001
1002         if (depth == 0)
1003                 return NULL;
1004
1005         /* Allocate the required arrays. */
1006
1007         oa = builtin_anewarray(2, arrayclass_java_lang_Object);
1008
1009         if (oa == NULL)
1010                 goto return_NULL;
1011
1012         classes = builtin_anewarray(depth, class_java_lang_Class);
1013
1014         if (classes == NULL)
1015                 goto return_NULL;
1016
1017         methodnames = builtin_anewarray(depth, class_java_lang_String);
1018
1019         if (methodnames == NULL)
1020                 goto return_NULL;
1021
1022         /* Set up the 2-dimensional array. */
1023
1024         array_objectarray_element_set(oa, 0, (java_handle_t *) classes);
1025         array_objectarray_element_set(oa, 1, (java_handle_t *) methodnames);
1026
1027         /* Iterate over the whole stack. */
1028         /* TODO We should use a critical section here to speed things
1029            up. */
1030
1031         i = 0;
1032
1033         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1034                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1035                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1036                 /* Get the methodinfo. */
1037
1038                 m = tmpsfi.code->m;
1039
1040                 /* Skip builtin methods. */
1041
1042                 if (m->flags & ACC_METHOD_BUILTIN)
1043                         continue;
1044
1045                 /* Store the class in the array. */
1046                 /* NOTE: We use a LLNI-macro here, because a classinfo is not
1047                    a handle. */
1048
1049                 LLNI_array_direct(classes, i) = (java_object_t *) m->clazz;
1050
1051                 /* Store the name in the array. */
1052
1053                 string = javastring_new(m->name);
1054
1055                 if (string == NULL)
1056                         goto return_NULL;
1057
1058                 array_objectarray_element_set(methodnames, i, string);
1059
1060                 i++;
1061         }
1062
1063         CYCLES_STATS_END(stacktrace_get_stack)
1064
1065         return oa;
1066
1067 return_NULL:
1068         CYCLES_STATS_END(stacktrace_get_stack)
1069
1070         return NULL;
1071 }
1072 #endif
1073
1074
1075 /* stacktrace_print_entry ****************************************************
1076
1077    Print line for a stacktrace entry.
1078
1079    ARGUMENTS:
1080        m ............ methodinfo of the entry
1081        linenumber ... linenumber of the entry
1082
1083 *******************************************************************************/
1084
1085 static void stacktrace_print_entry(methodinfo *m, int32_t linenumber)
1086 {
1087         /* Sanity check. */
1088
1089         assert(m != NULL);
1090
1091         printf("\tat ");
1092
1093         if (m->flags & ACC_METHOD_BUILTIN)
1094                 printf("NULL");
1095         else
1096                 utf_display_printable_ascii_classname(m->clazz->name);
1097
1098         printf(".");
1099         utf_display_printable_ascii(m->name);
1100         utf_display_printable_ascii(m->descriptor);
1101
1102         if (m->flags & ACC_NATIVE) {
1103                 puts("(Native Method)");
1104         }
1105         else {
1106                 if (m->flags & ACC_METHOD_BUILTIN) {
1107                         puts("(builtin)");
1108                 }
1109                 else {
1110                         printf("(");
1111                         utf_display_printable_ascii(m->clazz->sourcefile);
1112                         printf(":%d)\n", linenumber);
1113                 }
1114         }
1115
1116         fflush(stdout);
1117 }
1118
1119
1120 /* stacktrace_print ************************************************************
1121
1122    Print the given stacktrace with CACAO intern methods only (no Java
1123    code required).
1124
1125    This method is used by stacktrace_dump_trace and
1126    builtin_trace_exception.
1127
1128    IN:
1129        st ... stacktrace to print
1130
1131 *******************************************************************************/
1132
1133 void stacktrace_print(stacktrace_t *st)
1134 {
1135         stacktrace_entry_t *ste;
1136         methodinfo         *m;
1137         int32_t             linenumber;
1138         int                 i;
1139
1140         ste = &(st->entries[0]);
1141
1142         for (i = 0; i < st->length; i++, ste++) {
1143                 m = ste->code->m;
1144
1145                 /* Get the line number. */
1146
1147                 linenumber = linenumbertable_linenumber_for_pc(&m, ste->code, ste->pc);
1148
1149                 stacktrace_print_entry(m, linenumber);
1150         }
1151 }
1152
1153
1154 /* stacktrace_print_current ****************************************************
1155
1156    Print the current stacktrace of the current thread.
1157
1158    NOTE: This function prints all frames of the stacktrace and does
1159    not skip frames like stacktrace_get.
1160
1161 *******************************************************************************/
1162
1163 void stacktrace_print_current(void)
1164 {
1165         stackframeinfo_t *sfi;
1166         stackframeinfo_t  tmpsfi;
1167         codeinfo         *code;
1168         methodinfo       *m;
1169         int32_t           linenumber;
1170
1171         sfi = threads_get_current_stackframeinfo();
1172
1173         if (sfi == NULL) {
1174                 puts("\t<<No stacktrace available>>");
1175                 fflush(stdout);
1176                 return;
1177         }
1178
1179         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1180                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1181                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1182                 /* Get the methodinfo. */
1183
1184                 code = tmpsfi.code;
1185                 m    = code->m;
1186
1187                 /* Get the line number. */
1188
1189                 linenumber = linenumbertable_linenumber_for_pc(&m, code, tmpsfi.xpc);
1190
1191                 stacktrace_print_entry(m, linenumber);
1192         }
1193 }
1194
1195
1196 /* stacktrace_print_of_thread **************************************************
1197
1198    Print the current stacktrace of the given thread.
1199
1200    ARGUMENTS:
1201        t ... thread
1202
1203 *******************************************************************************/
1204
1205 #if defined(ENABLE_THREADS)
1206 void stacktrace_print_of_thread(threadobject *t)
1207 {
1208         stackframeinfo_t *sfi;
1209         stackframeinfo_t  tmpsfi;
1210         codeinfo         *code;
1211         methodinfo       *m;
1212         int32_t           linenumber;
1213
1214         /* Build a stacktrace for the passed thread. */
1215
1216         sfi = t->_stackframeinfo;
1217         
1218         if (sfi == NULL) {
1219                 puts("\t<<No stacktrace available>>");
1220                 fflush(stdout);
1221                 return;
1222         }
1223
1224         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1225                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1226                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1227                 /* Get the methodinfo. */
1228
1229                 code = tmpsfi.code;
1230                 m    = code->m;
1231
1232                 /* Get the line number. */
1233
1234                 linenumber = linenumbertable_linenumber_for_pc(&m, code, tmpsfi.xpc);
1235
1236                 stacktrace_print_entry(m, linenumber);
1237         }
1238 }
1239 #endif
1240
1241
1242 /* stacktrace_print_exception **************************************************
1243
1244    Print the stacktrace of a given exception (more or less a wrapper
1245    to stacktrace_print).
1246
1247    IN:
1248        h ... handle of exception to print
1249
1250 *******************************************************************************/
1251
1252 void stacktrace_print_exception(java_handle_t *h)
1253 {
1254         java_lang_Throwable     *o;
1255
1256 #if defined(WITH_CLASSPATH_GNU)
1257         java_lang_VMThrowable   *vmt;
1258 #endif
1259
1260         java_lang_Object        *backtrace;
1261         java_handle_bytearray_t *ba;
1262         stacktrace_t            *st;
1263
1264         o = (java_lang_Throwable *) h;
1265
1266         if (o == NULL)
1267                 return;
1268
1269         /* now print the stacktrace */
1270
1271 #if defined(WITH_CLASSPATH_GNU)
1272
1273         LLNI_field_get_ref(o,   vmState, vmt);
1274         LLNI_field_get_ref(vmt, vmdata,  backtrace);
1275
1276 #elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
1277
1278         LLNI_field_get_ref(o, backtrace, backtrace);
1279
1280 #else
1281 # error unknown classpath configuration
1282 #endif
1283
1284         ba = (java_handle_bytearray_t *) backtrace;
1285
1286         /* Sanity check. */
1287
1288         assert(ba != NULL);
1289
1290         /* We need a critical section here as we use the byte-array data
1291            pointer directly. */
1292
1293         LLNI_CRITICAL_START;
1294         
1295         st = (stacktrace_t *) LLNI_array_data(ba);
1296
1297         stacktrace_print(st);
1298
1299         LLNI_CRITICAL_END;
1300 }
1301
1302
1303 #if defined(ENABLE_CYCLES_STATS)
1304 void stacktrace_print_cycles_stats(FILE *file)
1305 {
1306         CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead, file);
1307         CYCLES_STATS_PRINT(stacktrace_get,               file);
1308         CYCLES_STATS_PRINT(stacktrace_getClassContext ,  file);
1309         CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,  file);
1310         CYCLES_STATS_PRINT(stacktrace_get_stack,         file);
1311 }
1312 #endif
1313
1314
1315 /*
1316  * These are local overrides for various environment variables in Emacs.
1317  * Please do not remove this and leave it at the end of the file, where
1318  * Emacs will automagically detect them.
1319  * ---------------------------------------------------------------------
1320  * Local variables:
1321  * mode: c
1322  * indent-tabs-mode: t
1323  * c-basic-offset: 4
1324  * tab-width: 4
1325  * End:
1326  * vim:noexpandtab:sw=4:ts=4:
1327  */