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