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