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