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