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