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