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