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