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