* src/vm/options.h (opt_verify): Only declare for ENABLE_VERIFIER.
[cacao.git] / src / vm / jit / stacktrace.c
1 /* src/vm/jit/stacktrace.c - machine independet stacktrace system
2
3    Copyright (C) 1996-2005, 2006 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    Contact: cacao@cacaojvm.org
26
27    Authors: Joseph Wenninger
28
29    Changes: Christian Thalinger
30             Edwin Steiner
31
32    $Id: stacktrace.c 4833 2006-04-25 12:00:58Z edwin $
33
34 */
35
36
37 #include "config.h"
38
39 #include <assert.h>
40 #include <stdlib.h>
41 #include <string.h>
42
43 #include "vm/types.h"
44
45 #include "mm/boehm.h"
46 #include "mm/memory.h"
47 #include "native/native.h"
48
49 #include "vm/global.h"                   /* required here for native includes */
50 #include "native/include/java_lang_ClassLoader.h"
51 #include "native/include/java_lang_Throwable.h"
52 #include "native/include/java_lang_VMThrowable.h"
53
54 #if defined(USE_THREADS)
55 # if defined(NATIVE_THREADS)
56 #  include "threads/native/threads.h"
57 # else
58 #  include "threads/green/threads.h"
59 # endif
60 #else
61 # include "threads/none/threads.h"
62 #endif
63
64 #include "toolbox/logging.h"
65 #include "vm/builtin.h"
66 #include "vm/class.h"
67 #include "vm/exceptions.h"
68 #include "vm/loader.h"
69 #include "vm/options.h"
70 #include "vm/stringlocal.h"
71 #include "vm/vm.h"
72 #include "vm/jit/asmpart.h"
73 #include "vm/jit/codegen-common.h"
74 #include "vm/jit/methodheader.h"
75 #include "vm/cycles-stats.h"
76
77
78 /* linenumbertable_entry ******************************************************/
79
80 /* Keep the type of line the same as the pointer type, otherwise we
81    run into alignment troubles (like on MIPS64). */
82
83 typedef struct linenumbertable_entry linenumbertable_entry;
84
85 struct linenumbertable_entry {
86         ptrint  line;               /* NOTE: see doc/inlining_stacktrace.txt for  */
87         u1     *pc;                 /*       special meanings of line and pc.     */
88 };
89
90 /* global variables ***********************************************************/
91
92 #if !defined(USE_THREADS)
93 stackframeinfo *_no_threads_stackframeinfo = NULL;
94 #endif
95
96 CYCLES_STATS_DECLARE(stacktrace_overhead        ,100,1)
97 CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace,40,5000)
98 CYCLES_STATS_DECLARE(stacktrace_getClassContext ,40,5000)
99 CYCLES_STATS_DECLARE(stacktrace_getCurrentClass ,40,5000)
100 CYCLES_STATS_DECLARE(stacktrace_getStack        ,40,10000)
101
102
103 /* stacktrace_create_stackframeinfo ********************************************
104
105    Creates an stackframe info structure for inline code in the
106    interpreter.
107
108 *******************************************************************************/
109
110 #if defined(ENABLE_INTRP)
111 void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv, u1 *sp,
112                                                                           u1 *ra)
113 {
114         stackframeinfo **psfi;
115         methodinfo      *m;
116
117         /* get current stackframe info pointer */
118
119         psfi = STACKFRAMEINFO;
120
121         /* if we don't have pv handy */
122
123         if (pv == NULL) {
124 #if defined(ENABLE_INTRP)
125                 if (opt_intrp)
126                         pv = codegen_findmethod(ra);
127                 else
128 #endif
129                         {
130 #if defined(ENABLE_JIT)
131                                 pv = md_codegen_findmethod(ra);
132 #endif
133                         }
134         }
135
136         /* get methodinfo pointer from data segment */
137
138         m = *((methodinfo **) (pv + MethodPointer));
139
140         /* fill new stackframe info structure */
141
142         sfi->prev   = *psfi;
143         sfi->method = m;
144         sfi->pv     = pv;
145         sfi->sp     = sp;
146         sfi->ra     = ra;
147
148         /* xpc is the same as ra, but is required in stacktrace_create */
149
150         sfi->xpc    = ra;
151
152         /* store new stackframe info pointer */
153
154         *psfi = sfi;
155 }
156 #endif /* defined(ENABLE_INTRP) */
157
158
159 /* stacktrace_create_inline_stackframeinfo *************************************
160
161    Creates an stackframe info structure for an inline exception stub.
162
163 *******************************************************************************/
164
165 void stacktrace_create_inline_stackframeinfo(stackframeinfo *sfi, u1 *pv,
166                                                                                          u1 *sp, u1 *ra, u1 *xpc)
167 {
168         stackframeinfo **psfi;
169
170         /* get current stackframe info pointer */
171
172         psfi = STACKFRAMEINFO;
173
174 #if defined(ENABLE_INTRP)
175         if (opt_intrp) {
176                 /* if we don't have pv handy */
177
178                 if (pv == NULL)
179                         pv = codegen_findmethod(ra);
180
181         }
182 #endif
183
184         /* fill new stackframe info structure */
185
186         sfi->prev   = *psfi;
187         sfi->method = NULL;
188         sfi->pv     = pv;
189         sfi->sp     = sp;
190         sfi->ra     = ra;
191         sfi->xpc    = xpc;
192
193         /* store new stackframe info pointer */
194
195         *psfi = sfi;
196 }
197
198
199 /* stacktrace_create_extern_stackframeinfo *************************************
200
201    Creates an stackframe info structure for an extern exception
202    (hardware or assembler).
203
204 *******************************************************************************/
205
206 void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
207                                                                                          u1 *sp, u1 *ra, u1 *xpc)
208 {
209         stackframeinfo **psfi;
210 #if !defined(__I386__) && !defined(__X86_64__)
211         bool             isleafmethod;
212 #endif
213 #if defined(ENABLE_JIT)
214         s4               framesize;
215 #endif
216
217         /* get current stackframe info pointer */
218
219         psfi = STACKFRAMEINFO;
220
221         /* sometimes we don't have pv handy (e.g. in asmpart.S:
222        L_asm_call_jit_compiler_exception or in the interpreter). */
223
224         if (pv == NULL) {
225 #if defined(ENABLE_INTRP)
226                 if (opt_intrp)
227                         pv = codegen_findmethod(ra);
228                 else
229 #endif
230                         {
231 #if defined(ENABLE_JIT)
232                                 pv = md_codegen_findmethod(ra);
233 #endif
234                         }
235         }
236
237 #if defined(ENABLE_JIT)
238 # if defined(ENABLE_INTRP)
239         /* When using the interpreter, we pass RA to the function. */
240
241         if (!opt_intrp) {
242 # endif
243 # if defined(__I386__) || defined(__X86_64__)
244                 /* On i386 and x86_64 we always have to get the return address
245                    from the stack. */
246
247                 framesize = *((u4 *) (pv + FrameSize));
248
249                 ra = md_stacktrace_get_returnaddress(sp, framesize);
250 # else
251                 /* If the method is a non-leaf function, we need to get the return
252                    address from the stack. For leaf functions the return address
253                    is set correctly. This makes the assembler and the signal
254                    handler code simpler. */
255
256                 isleafmethod = *((s4 *) (pv + IsLeaf));
257
258                 if (!isleafmethod) {
259                         framesize = *((u4 *) (pv + FrameSize));
260
261                         ra = md_stacktrace_get_returnaddress(sp, framesize);
262                 }
263 # endif
264 # if defined(ENABLE_INTRP)
265         }
266 # endif
267 #endif /* defined(ENABLE_JIT) */
268
269         /* fill new stackframe info structure */
270
271         sfi->prev   = *psfi;
272         sfi->method = NULL;
273         sfi->pv     = pv;
274         sfi->sp     = sp;
275         sfi->ra     = ra;
276         sfi->xpc    = xpc;
277
278         /* store new stackframe info pointer */
279
280         *psfi = sfi;
281 }
282
283
284 /* stacktrace_create_native_stackframeinfo *************************************
285
286    Creates a stackframe info structure for a native stub.
287
288 *******************************************************************************/
289
290 void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv,
291                                                                                          u1 *sp, u1 *ra)
292 {
293         stackframeinfo **psfi;
294         methodinfo      *m;
295
296         /* get methodinfo pointer from data segment */
297
298         m = *((methodinfo **) (pv + MethodPointer));
299
300         /* get current stackframe info pointer */
301
302         psfi = STACKFRAMEINFO;
303
304         /* fill new stackframe info structure */
305
306         sfi->prev   = *psfi;
307         sfi->method = m;
308         sfi->pv     = NULL;
309         sfi->sp     = sp;
310         sfi->ra     = ra;
311         sfi->xpc    = NULL;
312
313         /* store new stackframe info pointer */
314
315         *psfi = sfi;
316 }
317
318
319 /* stacktrace_remove_stackframeinfo ********************************************
320
321    XXX
322
323 *******************************************************************************/
324
325 void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
326 {
327         stackframeinfo **psfi;
328
329         /* get current stackframe info pointer */
330
331         psfi = STACKFRAMEINFO;
332
333         /* restore the old pointer */
334
335         *psfi = sfi->prev;
336 }
337
338
339 /* stacktrace_inline_arithmeticexception ***************************************
340
341    Creates an ArithemticException for inline stub.
342
343 *******************************************************************************/
344
345 java_objectheader *stacktrace_inline_arithmeticexception(u1 *pv, u1 *sp,
346                                                                                                                  u1 *ra, u1 *xpc)
347 {
348         stackframeinfo     sfi;
349         java_objectheader *o;
350
351         /* create stackframeinfo */
352
353         stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
354
355         /* create exception */
356
357         o = new_arithmeticexception();
358
359         /* remove stackframeinfo */
360
361         stacktrace_remove_stackframeinfo(&sfi);
362
363         return o;
364 }
365
366
367 /* stacktrace_inline_arrayindexoutofboundsexception ****************************
368
369    Creates an ArrayIndexOutOfBoundsException for inline stub.
370
371 *******************************************************************************/
372
373 java_objectheader *stacktrace_inline_arrayindexoutofboundsexception(u1 *pv,
374                                                                                                                                         u1 *sp,
375                                                                                                                                         u1 *ra,
376                                                                                                                                         u1 *xpc,
377                                                                                                                                         s4 index)
378 {
379         stackframeinfo     sfi;
380         java_objectheader *o;
381
382         /* create stackframeinfo */
383
384         stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
385
386         /* create exception */
387
388         o = new_arrayindexoutofboundsexception(index);
389
390         /* remove stackframeinfo */
391
392         stacktrace_remove_stackframeinfo(&sfi);
393
394         return o;
395 }
396
397
398 /* stacktrace_inline_arraystoreexception ***************************************
399
400    Creates an ArrayStoreException for inline stub.
401
402 *******************************************************************************/
403
404 java_objectheader *stacktrace_inline_arraystoreexception(u1 *pv, u1 *sp, u1 *ra,
405                                                                                                                  u1 *xpc)
406 {
407         stackframeinfo     sfi;
408         java_objectheader *o;
409
410         /* create stackframeinfo */
411
412         stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
413
414         /* create exception */
415
416         o = new_arraystoreexception();
417
418         /* remove stackframeinfo */
419
420         stacktrace_remove_stackframeinfo(&sfi);
421
422         return o;
423 }
424
425
426 /* stacktrace_inline_classcastexception ****************************************
427
428    Creates an ClassCastException for inline stub.
429
430 *******************************************************************************/
431
432 java_objectheader *stacktrace_inline_classcastexception(u1 *pv, u1 *sp, u1 *ra,
433                                                                                                                 u1 *xpc)
434 {
435         stackframeinfo     sfi;
436         java_objectheader *o;
437
438         /* create stackframeinfo */
439
440         stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
441
442         /* create exception */
443
444         o = new_classcastexception();
445
446         /* remove stackframeinfo */
447
448         stacktrace_remove_stackframeinfo(&sfi);
449
450         return o;
451 }
452
453
454 /* stacktrace_inline_nullpointerexception **************************************
455
456    Creates an NullPointerException for inline stub.
457
458 *******************************************************************************/
459
460 java_objectheader *stacktrace_inline_nullpointerexception(u1 *pv, u1 *sp,
461                                                                                                                   u1 *ra, u1 *xpc)
462 {
463         stackframeinfo     sfi;
464         java_objectheader *o;
465
466         /* create stackframeinfo */
467
468         stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
469
470         /* create exception */
471
472         o = new_nullpointerexception();
473
474         /* remove stackframeinfo */
475
476         stacktrace_remove_stackframeinfo(&sfi);
477
478         return o;
479 }
480
481
482 /* stacktrace_inline_fillInStackTrace ******************************************
483
484    Fills in the correct stacktrace into an existing exception object
485    (this one is for inline exception stubs).
486
487 *******************************************************************************/
488
489 java_objectheader *stacktrace_inline_fillInStackTrace(u1 *pv, u1 *sp, u1 *ra,
490                                                                                                           u1 *xpc)
491 {
492         stackframeinfo     sfi;
493         java_objectheader *o;
494         methodinfo        *m;
495
496         /* create stackframeinfo */
497
498         stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
499
500         /* get exception */
501
502         o = *exceptionptr;
503         assert(o);
504
505         /* clear exception */
506
507         *exceptionptr = NULL;
508
509         /* resolve methodinfo pointer from exception object */
510
511         m = class_resolvemethod(o->vftbl->class,
512                                                         utf_fillInStackTrace,
513                                                         utf_void__java_lang_Throwable);
514
515         /* call function */
516
517         (void) vm_call_method(m, o);
518
519         /* remove stackframeinfo */
520
521         stacktrace_remove_stackframeinfo(&sfi);
522
523         return o;
524 }
525
526
527 /* stacktrace_hardware_arithmeticexception *************************************
528
529    Creates an ArithemticException for inline stub.
530
531 *******************************************************************************/
532
533 java_objectheader *stacktrace_hardware_arithmeticexception(u1 *pv, u1 *sp,
534                                                                                                                    u1 *ra, u1 *xpc)
535 {
536         stackframeinfo     sfi;
537         java_objectheader *o;
538
539         /* create stackframeinfo */
540
541         stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
542
543         /* create exception */
544
545         o = new_arithmeticexception();
546
547         /* remove stackframeinfo */
548
549         stacktrace_remove_stackframeinfo(&sfi);
550
551         return o;
552 }
553
554
555 /* stacktrace_hardware_nullpointerexception ************************************
556
557    Creates an NullPointerException for the SIGSEGV signal handler.
558
559 *******************************************************************************/
560
561 java_objectheader *stacktrace_hardware_nullpointerexception(u1 *pv, u1 *sp,
562                                                                                                                         u1 *ra, u1 *xpc)
563 {
564         stackframeinfo     sfi;
565         java_objectheader *o;
566
567         /* create stackframeinfo */
568
569         stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
570
571         /* create exception */
572
573         o = new_nullpointerexception();
574
575         /* remove stackframeinfo */
576
577         stacktrace_remove_stackframeinfo(&sfi);
578
579         return o;
580 }
581
582
583 /* stacktrace_add_entry ********************************************************
584
585    Adds a new entry to the stacktrace buffer.
586
587 *******************************************************************************/
588
589 static void stacktrace_add_entry(stacktracebuffer *stb, methodinfo *m, u2 line)
590 {
591         stacktrace_entry *ste;
592
593         /* check if we already reached the buffer capacity */
594
595         if (stb->used >= stb->capacity) {
596                 /* reallocate new memory */
597
598                 stb->entries = DMREALLOC(stb->entries, stacktrace_entry, stb->capacity,
599                                                                  stb->capacity + STACKTRACE_CAPACITY_INCREMENT);
600
601                 /* set new buffer capacity */
602
603                 stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
604         }
605
606         /* insert the current entry */
607
608         ste = &(stb->entries[stb->used]);
609
610         ste->method     = m;
611         ste->linenumber = line;
612
613         /* increase entries used count */
614
615         stb->used += 1;
616 }
617
618
619 /* stacktrace_add_method_intern ************************************************
620
621    This function is used by stacktrace_add_method to search the line number
622    table for the line corresponding to a given pc. The function recurses for
623    inlined methods.
624
625 *******************************************************************************/
626
627 static bool stacktrace_add_method_intern(stacktracebuffer *stb, 
628                                                                                  methodinfo *m, 
629                                                                                  linenumbertable_entry *lntentry,
630                                                                                  ptrint lntsize,
631                                                                                  u1 *pc)
632 {
633         linenumbertable_entry *lntinline;   /* special entry for inlined method */
634
635         assert(stb);
636         assert(lntentry);
637
638         /* Find the line number for the specified PC (going backwards
639            in the linenumber table). The linenumber table size is zero
640            in native stubs. */
641
642         for (; lntsize > 0; lntsize--, lntentry--) {
643
644                 /* did we reach the current line? */
645
646                 /* Note: In case of inlining this may actually compare the pc
647                    against a methodinfo *, yielding a non-sensical
648                    result. This is no problem, however, as we ignore such
649                    entries in the switch below. This way we optimize for the
650                    common case (ie. a real pc in lntentry->pc). */
651
652                 if (pc >= lntentry->pc) {
653
654                         /* check for special inline entries (see
655                            doc/inlining_stacktrace.txt for details */
656
657                         if ((s4)lntentry->line < 0) {
658                                 switch (lntentry->line) {
659                                         case -1: 
660                                                 /* begin of inlined method (ie. INLINE_END
661                                                    instruction) */
662
663                                                 lntinline = --lntentry;/* get entry with methodinfo * */
664                                                 lntentry--;            /* skip the special entry      */
665                                                 lntsize -= 2;
666
667                                                 /* search inside the inlined method */
668                                                 if (stacktrace_add_method_intern(
669                                                                         stb, 
670                                                                         (methodinfo*) lntinline->pc,
671                                                                         lntentry,
672                                                                         lntsize,
673                                                                         pc))
674                                                 {
675                                                         /* the inlined method contained the pc */
676                                                         assert(lntinline->line <= -3);
677                                                         stacktrace_add_entry(stb, m, (-3) - lntinline->line);
678                                                         return true;
679                                                 }
680                                                 /* pc was not in inlined method, continue
681                                                    search.  Entries inside the inlined method
682                                                    will be skipped because their lntentry->pc
683                                                    is higher than pc.  */
684                                                 break;
685
686                                         case -2: 
687                                                 /* end of inlined method */
688                                                 return false;
689
690                                         /* default: is only reached for an -3-line entry
691                                            after a skipped -2 entry. We can safely ignore
692                                            it and continue searching.  */
693                                 }
694                         }
695                         else {
696                                 /* found a normal entry */
697                                 stacktrace_add_entry(stb, m, lntentry->line);
698                                 return true;
699                         }
700                 }
701         }
702
703         /* not found */
704         return false;
705 }
706
707 /* stacktrace_add_method *******************************************************
708
709    Add stacktrace entries[1] for the given method to the stacktrace buffer.
710
711    IN:
712        stb.........stacktracebuffer to fill
713            m...........method for which entries should be created
714            pv..........pv of method
715            pc..........position of program counter within the method's code
716
717    OUT:
718        true, if stacktrace entries were successfully created, false otherwise.
719
720    [1] In case of inlined methods there may be more than one stacktrace
721        entry for a codegen-level method. (see doc/inlining_stacktrace.txt)
722
723 *******************************************************************************/
724
725 static bool stacktrace_add_method(stacktracebuffer *stb, methodinfo *m, u1 *pv,
726                                                                   u1 *pc)
727 {
728         ptrint                 lntsize;     /* size of line number table          */
729         u1                    *lntstart;    /* start of line number table         */
730         linenumbertable_entry *lntentry;    /* points to last entry in the table  */
731         codeinfo              *code;        /* compiled realization of method     */
732
733         /* get size of line number table */
734
735         lntsize  = *((ptrint *) (pv + LineNumberTableSize));
736         lntstart = *((u1 **)    (pv + LineNumberTableStart));
737
738         /* Subtract the size of the line number entry of the structure,
739            since the line number table start points to the pc. */
740
741         lntentry = (linenumbertable_entry *) (lntstart - SIZEOF_VOID_P);
742
743         /* find the realization of the method the pc is in    */
744         /* XXX Note: This is preliminary. It would be cleaner */
745         /* to get the codeinfo * from the PV                  */
746
747         code = m->code;
748         while (1) {
749                 if (!code) {
750 #ifndef NDEBUG
751                         method_println(m);
752                         dolog("Could not find codeinfo for Current PC: %p",(void*)pc);
753 #endif
754                         abort();
755                 }
756
757                 if (((ptrint)pc >= (ptrint)code->entrypoint)
758                                 &&
759                         ( (pc - (u1*)code->entrypoint) < code->mcodelength ))
760                 {
761                         /* found */
762                         break;
763                 }
764
765                 code = code->prev;
766         }
767
768         /* search the line number table */
769
770         if (stacktrace_add_method_intern(stb, m, lntentry, lntsize, pc))
771                 return true;
772
773         /* If we get here, just add the entry with line number 0. */
774
775         stacktrace_add_entry(stb, m, 0);
776
777         return true;
778 }
779
780
781 /* stacktrace_create ***********************************************************
782
783    Generates a stacktrace from the thread passed into a
784    stacktracebuffer.  The stacktracebuffer is allocated on the GC
785    heap.
786
787    RETURN VALUE:
788       pointer to the stacktracebuffer, or
789           NULL if an exception has been thrown
790
791 *******************************************************************************/
792
793 stacktracebuffer *stacktrace_create(threadobject* thread)
794 {
795         stacktracebuffer *stb;
796         stackframeinfo   *sfi;
797         methodinfo       *m;
798         u1               *pv;
799         u1               *sp;
800         u4                framesize;
801         u1               *ra;
802         u1               *xpc;
803
804         /* prevent compiler warnings */
805
806         pv = NULL;
807         sp = NULL;
808         ra = NULL;
809
810         /* create a stacktracebuffer in dump memory */
811
812         stb = DNEW(stacktracebuffer);
813
814         stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
815         stb->used     = 0;
816         stb->entries  = DMNEW(stacktrace_entry, STACKTRACE_CAPACITY_DEFAULT);
817
818         /* The first element in the stackframe chain must always be a
819            native stackframeinfo (VMThrowable.fillInStackTrace is a native
820            function). */
821
822 #if defined(USE_THREADS)
823         sfi = thread->info._stackframeinfo;
824 #else
825         sfi = _no_threads_stackframeinfo;
826 #endif
827
828 #define PRINTMETHODS 0
829
830 #if PRINTMETHODS
831         printf("\n\nfillInStackTrace start:\n");
832         fflush(stdout);
833 #endif
834
835         /* Loop while we have a method pointer (asm_calljavafunction has
836            NULL) or there is a stackframeinfo in the chain. */
837
838         m = NULL;
839
840         while (m || sfi) {
841                 /* m == NULL should only happen for the first time and inline
842                    stackframe infos, like from the exception stubs or the
843                    patcher wrapper. */
844
845                 if (m == NULL) {
846                         /* for native stub stackframe infos, pv is always NULL */
847
848                         if (sfi->pv == NULL) {
849                                 /* get methodinfo, sp and ra from the current stackframe info */
850
851                                 m  = sfi->method;
852                                 sp = sfi->sp;           /* sp of parent Java function         */
853                                 ra = sfi->ra;
854
855                                 if (m)
856                                         stacktrace_add_entry(stb, m, 0);
857
858 #if PRINTMETHODS
859                                 printf("ra=%p sp=%p, ", ra, sp);
860                                 method_print(m);
861                                 printf(": native stub\n");
862                                 fflush(stdout);
863 #endif
864                                 /* This is an native stub stackframe info, so we can
865                                    get the parent pv from the return address
866                                    (ICMD_INVOKE*). */
867
868 #if defined(ENABLE_INTRP)
869                                 if (opt_intrp)
870                                         pv = codegen_findmethod(ra);
871                                 else
872 #endif
873                                         {
874 #if defined(ENABLE_JIT)
875                                                 pv = md_codegen_findmethod(ra);
876 #endif
877                                         }
878
879                                 /* get methodinfo pointer from parent data segment */
880
881                                 m = *((methodinfo **) (pv + MethodPointer));
882
883                         } else {
884                                 /* Inline stackframe infos are special: they have a
885                                    xpc of the actual exception position and the return
886                                    address saved since an inline stackframe info can
887                                    also be in a leaf method (no return address saved
888                                    on stack!!!).  ATTENTION: This one is also for
889                                    hardware exceptions!!! */
890
891                                 /* get methodinfo, sp and ra from the current stackframe info */
892
893                                 m   = sfi->method;      /* m == NULL                          */
894                                 pv  = sfi->pv;          /* pv of parent Java function         */
895                                 sp  = sfi->sp;          /* sp of parent Java function         */
896                                 ra  = sfi->ra;          /* ra of parent Java function         */
897                                 xpc = sfi->xpc;         /* actual exception position          */
898
899 #if PRINTMETHODS
900                                 printf("ra=%p sp=%p, ", ra, sp);
901                                 printf("NULL: inline stub\n");
902                                 fflush(stdout);
903 #endif
904
905                                 /* get methodinfo from current Java method */
906
907                                 m = *((methodinfo **) (pv + MethodPointer));
908
909                                 /* if m == NULL, this is a asm_calljavafunction call */
910
911                                 if (m != NULL) {
912 #if PRINTMETHODS
913                                         printf("ra=%p sp=%p, ", ra, sp);
914                                         method_print(m);
915                                         printf(": inline stub parent");
916                                         fflush(stdout);
917 #endif
918
919 #if defined(ENABLE_INTRP)
920                                         if (!opt_intrp) {
921 #endif
922
923                                         /* add the method to the stacktrace */
924
925                                         stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) xpc));
926
927                                         /* get the current stack frame size */
928
929                                         framesize = *((u4 *) (pv + FrameSize));
930
931 #if PRINTMETHODS
932                                         printf(", framesize=%d\n", framesize);
933                                         fflush(stdout);
934 #endif
935
936                                         /* set stack pointer to stackframe of parent Java */
937                                         /* function of the current Java function */
938
939 #if defined(__I386__) || defined (__X86_64__)
940                                         sp += framesize + SIZEOF_VOID_P;
941 #else
942                                         sp += framesize;
943 #endif
944
945                                         /* get data segment and methodinfo pointer from parent */
946                                         /* method */
947
948 #if defined(ENABLE_JIT)
949                                         pv = md_codegen_findmethod(ra);
950 #endif
951
952                                         m = *((methodinfo **) (pv + MethodPointer));
953
954 #if defined(ENABLE_INTRP)
955                                         }
956 #endif
957                                 }
958 #if PRINTMETHODS
959                                 else {
960                                         printf("ra=%p sp=%p, ", ra, sp);
961                                         printf("asm_calljavafunction\n");
962                                         fflush(stdout);
963                                 }
964 #endif
965                         }
966
967                         /* get previous stackframeinfo in the chain */
968
969                         sfi = sfi->prev;
970
971                 } else {
972 #if PRINTMETHODS
973                         printf("ra=%p sp=%p, ", ra, sp);
974                         method_print(m);
975                         printf(": JIT");
976                         fflush(stdout);
977 #endif
978
979                         /* JIT method found, add it to the stacktrace (we subtract
980                            1 from the return address since it points the the
981                            instruction after call). */
982
983                         stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1);
984
985                         /* get the current stack frame size */
986
987                         framesize = *((u4 *) (pv + FrameSize));
988
989 #if PRINTMETHODS
990                         printf(", framesize=%d\n", framesize);
991                         fflush(stdout);
992 #endif
993
994                         /* get return address of current stack frame */
995
996 #if defined(ENABLE_JIT)
997 # if defined(ENABLE_INTRP)
998                         if (opt_intrp)
999                                 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
1000                         else
1001 # endif
1002                                 ra = md_stacktrace_get_returnaddress(sp, framesize);
1003 #else
1004                         ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
1005 #endif
1006
1007                         /* get data segment and methodinfo pointer from parent method */
1008
1009 #if defined(ENABLE_INTRP)
1010                         if (opt_intrp)
1011                                 pv = codegen_findmethod(ra);
1012                         else
1013 #endif
1014                                 {
1015 #if defined(ENABLE_JIT)
1016                                         pv = md_codegen_findmethod(ra);
1017 #endif
1018                                 }
1019
1020                         m = *((methodinfo **) (pv + MethodPointer));
1021
1022                         /* walk the stack */
1023
1024 #if defined(ENABLE_INTRP)
1025                         if (opt_intrp)
1026                                 sp = *(u1 **) (sp - framesize);
1027                         else
1028 #endif
1029                                 {
1030 #if defined(__I386__) || defined (__X86_64__)
1031                                         sp += framesize + SIZEOF_VOID_P;
1032 #else
1033                                         sp += framesize;
1034 #endif
1035                                 }
1036                 }
1037         }
1038
1039         /* return the stacktracebuffer */
1040
1041         return stb;
1042 }
1043
1044
1045 /* stacktrace_fillInStackTrace *************************************************
1046
1047    Generate a stacktrace from the current thread for
1048    java.lang.VMThrowable.fillInStackTrace.
1049
1050 *******************************************************************************/
1051
1052 stacktracebuffer *stacktrace_fillInStackTrace(void)
1053 {
1054         stacktracebuffer *stb;
1055         stacktracebuffer *gcstb;
1056         s4                dumpsize;
1057         CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
1058
1059         /* mark start of dump memory area */
1060
1061         dumpsize = dump_size();
1062
1063         /* create a stacktrace from the current thread */
1064
1065         stb = stacktrace_create(THREADOBJECT);
1066         if (!stb)
1067                 goto return_NULL;
1068
1069         /* allocate memory from the GC heap and copy the stacktrace buffer */
1070
1071         gcstb = GCNEW(stacktracebuffer);
1072
1073         if (gcstb == NULL)
1074                 goto return_NULL;
1075
1076         gcstb->capacity = stb->capacity;
1077         gcstb->used     = stb->used;
1078         gcstb->entries  = GCMNEW(stacktrace_entry, stb->used);
1079
1080         if (gcstb->entries == NULL)
1081                 goto return_NULL;
1082
1083         MCOPY(gcstb->entries, stb->entries, stacktrace_entry, stb->used);
1084
1085         /* release dump memory */
1086
1087         dump_release(dumpsize);
1088
1089         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
1090                                                                    stacktrace_overhead)
1091         return gcstb;
1092
1093 return_NULL:
1094         dump_release(dumpsize);
1095
1096         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
1097                                                                    stacktrace_overhead)
1098
1099         return NULL;
1100 }
1101
1102
1103 /* stacktrace_getClassContext **************************************************
1104
1105    Creates a Class context array.
1106
1107    RETURN VALUE:
1108       the array of java.lang.Class objects, or
1109           NULL if an exception has been thrown
1110
1111 *******************************************************************************/
1112
1113 java_objectarray *stacktrace_getClassContext(void)
1114 {
1115         stacktracebuffer  *stb;
1116         stacktrace_entry  *ste;
1117         java_objectarray  *oa;
1118         s4                 oalength;
1119         s4                 i;
1120         s4                 dumpsize;
1121         CYCLES_STATS_DECLARE_AND_START
1122
1123         /* mark start of dump memory area */
1124
1125         dumpsize = dump_size();
1126
1127         /* create a stacktrace for the current thread */
1128
1129         stb = stacktrace_create(THREADOBJECT);
1130         if (!stb)
1131                 goto return_NULL;
1132
1133         /* calculate the size of the Class array */
1134
1135         for (i = 0, oalength = 0; i < stb->used; i++)
1136                 if (stb->entries[i].method != NULL)
1137                         oalength++;
1138
1139         ste = &(stb->entries[0]);
1140         ste++;
1141         oalength--;
1142
1143         /* XXX document me */
1144
1145         if (oalength > 0) {
1146                 if (ste->method &&
1147                         (ste->method->class == class_java_lang_SecurityManager)) {
1148                         ste++;
1149                         oalength--;
1150                 }
1151         }
1152
1153         /* allocate the Class array */
1154
1155         oa = builtin_anewarray(oalength, class_java_lang_Class);
1156         if (!oa)
1157                 goto return_NULL;
1158
1159         /* fill the Class array from the stacktracebuffer */
1160
1161         for(i = 0; i < oalength; i++, ste++) {
1162                 if (ste->method == NULL) {
1163                         i--;
1164                         continue;
1165                 }
1166
1167                 oa->data[i] = (java_objectheader *) ste->method->class;
1168         }
1169
1170         /* release dump memory */
1171
1172         dump_release(dumpsize);
1173
1174         CYCLES_STATS_END(stacktrace_getClassContext)
1175
1176         return oa;
1177
1178 return_NULL:
1179         dump_release(dumpsize);
1180
1181         CYCLES_STATS_END(stacktrace_getClassContext)
1182
1183         return NULL;
1184 }
1185
1186
1187 /* stacktrace_getCurrentClass **************************************************
1188
1189    Find the current class by walking the stack trace.
1190
1191    Quote from the JNI documentation:
1192          
1193    In the Java 2 Platform, FindClass locates the class loader
1194    associated with the current native method.  If the native code
1195    belongs to a system class, no class loader will be
1196    involved. Otherwise, the proper class loader will be invoked to
1197    load and link the named class. When FindClass is called through the
1198    Invocation Interface, there is no current native method or its
1199    associated class loader. In that case, the result of
1200    ClassLoader.getBaseClassLoader is used."
1201
1202 *******************************************************************************/
1203
1204 classinfo *stacktrace_getCurrentClass(void)
1205 {
1206         stacktracebuffer  *stb;
1207         stacktrace_entry  *ste;
1208         methodinfo        *m;
1209         s4                 i;
1210         s4                 dumpsize;
1211         CYCLES_STATS_DECLARE_AND_START
1212
1213         /* mark start of dump memory area */
1214
1215         dumpsize = dump_size();
1216
1217         /* create a stacktrace for the current thread */
1218
1219         stb = stacktrace_create(THREADOBJECT);
1220         if (!stb)
1221                 goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
1222
1223         /* iterate over all stacktrace entries and find the first suitable
1224            class */
1225
1226         for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
1227                 m = ste->method;
1228
1229                 if (m == NULL)
1230                         continue;
1231
1232                 if (m->class == class_java_security_PrivilegedAction)
1233                         goto return_NULL;
1234
1235                 if (m->class != NULL) {
1236                         dump_release(dumpsize);
1237
1238                         CYCLES_STATS_END(stacktrace_getCurrentClass)
1239
1240                         return m->class;
1241                 }
1242         }
1243
1244         /* no Java method found on the stack */
1245
1246 return_NULL:
1247         dump_release(dumpsize);
1248
1249         CYCLES_STATS_END(stacktrace_getCurrentClass)
1250
1251         return NULL;
1252 }
1253
1254
1255 /* stacktrace_getStack *********************************************************
1256
1257    Create a 2-dimensional array for java.security.VMAccessControler.
1258
1259    RETURN VALUE:
1260       the arrary, or
1261           NULL if an exception has been thrown
1262
1263 *******************************************************************************/
1264
1265 java_objectarray *stacktrace_getStack(void)
1266 {
1267         stacktracebuffer *stb;
1268         stacktrace_entry *ste;
1269         java_objectarray *oa;
1270         java_objectarray *classes;
1271         java_objectarray *methodnames;
1272         classinfo        *c;
1273         java_lang_String *str;
1274         s4                i;
1275         s4                dumpsize;
1276         CYCLES_STATS_DECLARE_AND_START
1277
1278         /* mark start of dump memory area */
1279
1280         dumpsize = dump_size();
1281
1282         /* create a stacktrace for the current thread */
1283
1284         stb = stacktrace_create(THREADOBJECT);
1285         if (!stb)
1286                 goto return_NULL;
1287
1288         /* get the first stacktrace entry */
1289
1290         ste = &(stb->entries[0]);
1291
1292         /* allocate all required arrays */
1293
1294         oa = builtin_anewarray(2, arrayclass_java_lang_Object);
1295
1296         if (!oa)
1297                 goto return_NULL;
1298
1299         classes = builtin_anewarray(stb->used, class_java_lang_Class);
1300
1301         if (!classes)
1302                 goto return_NULL;
1303
1304         methodnames = builtin_anewarray(stb->used, class_java_lang_String);
1305
1306         if (!methodnames)
1307                 goto return_NULL;
1308
1309         /* set up the 2-dimensional array */
1310
1311         oa->data[0] = (java_objectheader *) classes;
1312         oa->data[1] = (java_objectheader *) methodnames;
1313
1314         /* iterate over all stacktrace entries */
1315
1316         for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
1317                 c = ste->method->class;
1318
1319                 classes->data[i] = (java_objectheader *) c;
1320                 str = javastring_new(ste->method->name);
1321
1322                 if (!str)
1323                         goto return_NULL;
1324
1325                 methodnames->data[i] = (java_objectheader *) str;
1326         }
1327
1328         /* return the 2-dimensional array */
1329
1330         dump_release(dumpsize);
1331
1332         CYCLES_STATS_END(stacktrace_getStack)
1333
1334         return oa;
1335
1336 return_NULL:
1337         dump_release(dumpsize);
1338
1339         CYCLES_STATS_END(stacktrace_getStack)
1340
1341         return NULL;
1342 }
1343
1344
1345 /* stacktrace_print_trace_from_buffer ******************************************
1346
1347    Print the stacktrace of a given stacktracebuffer with CACAO intern
1348    methods (no Java help). This method is used by
1349    stacktrace_dump_trace and builtin_trace_exception.
1350
1351 *******************************************************************************/
1352
1353 static void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
1354 {
1355         stacktrace_entry *ste;
1356         methodinfo       *m;
1357         s4                i;
1358
1359         ste = &(stb->entries[0]);
1360
1361         for (i = 0; i < stb->used; i++, ste++) {
1362                 m = ste->method;
1363
1364                 printf("\tat ");
1365                 utf_display_classname(m->class->name);
1366                 printf(".");
1367                 utf_display(m->name);
1368                 utf_display(m->descriptor);
1369
1370                 if (m->flags & ACC_NATIVE) {
1371                         puts("(Native Method)");
1372
1373                 } else {
1374                         printf("(");
1375                         utf_display(m->class->sourcefile);
1376                         printf(":%d)\n", (u4) ste->linenumber);
1377                 }
1378         }
1379
1380         /* just to be sure */
1381
1382         fflush(stdout);
1383 }
1384
1385
1386 /* stacktrace_dump_trace *******************************************************
1387
1388    This method is call from signal_handler_sigusr1 to dump the
1389    stacktrace of the current thread to stdout.
1390
1391 *******************************************************************************/
1392
1393 void stacktrace_dump_trace(void)
1394 {
1395         stacktracebuffer *stb;
1396         s4                dumpsize;
1397
1398 #if 0
1399         /* get methodinfo pointer from data segment */
1400
1401         m = *((methodinfo **) (pv + MethodPointer));
1402
1403         /* get current stackframe info pointer */
1404
1405         psfi = STACKFRAMEINFO;
1406
1407         /* fill new stackframe info structure */
1408
1409         sfi->prev   = *psfi;
1410         sfi->method = NULL;
1411         sfi->pv     = NULL;
1412         sfi->sp     = sp;
1413         sfi->ra     = ra;
1414
1415         /* store new stackframe info pointer */
1416
1417         *psfi = sfi;
1418 #endif
1419
1420         /* mark start of dump memory area */
1421
1422         dumpsize = dump_size();
1423
1424         /* create a stacktrace for the current thread */
1425
1426         stb = stacktrace_create(THREADOBJECT);
1427
1428         /* print stacktrace */
1429
1430         if (stb) {
1431                 stacktrace_print_trace_from_buffer(stb);
1432
1433         } else {
1434                 puts("\t<<No stacktrace available>>");
1435                 fflush(stdout);
1436         }
1437
1438         dump_release(dumpsize);
1439 }
1440
1441
1442 /* stacktrace_print_trace ******************************************************
1443
1444    Print the stacktrace of a given exception. More or less a wrapper
1445    to stacktrace_print_trace_from_buffer.
1446
1447 *******************************************************************************/
1448
1449 void stacktrace_print_trace(java_objectheader *xptr)
1450 {
1451         java_lang_Throwable   *t;
1452         java_lang_VMThrowable *vmt;
1453         stacktracebuffer      *stb;
1454
1455         t = (java_lang_Throwable *) xptr;
1456
1457         if (t == NULL)
1458                 return;
1459
1460         /* now print the stacktrace */
1461
1462         vmt = t->vmState;
1463         stb = (stacktracebuffer *) vmt->vmData;
1464
1465         stacktrace_print_trace_from_buffer(stb);
1466 }
1467
1468
1469 #if defined(ENABLE_CYCLES_STATS)
1470 void stacktrace_print_cycles_stats(FILE *file)
1471 {
1472         CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
1473         CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
1474         CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
1475         CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
1476         CYCLES_STATS_PRINT(stacktrace_getStack        ,file);
1477 }
1478 #endif
1479
1480
1481 /*
1482  * These are local overrides for various environment variables in Emacs.
1483  * Please do not remove this and leave it at the end of the file, where
1484  * Emacs will automagically detect them.
1485  * ---------------------------------------------------------------------
1486  * Local variables:
1487  * mode: c
1488  * indent-tabs-mode: t
1489  * c-basic-offset: 4
1490  * tab-width: 4
1491  * End:
1492  * vim:noexpandtab:sw=4:ts=4:
1493  */