* src/vm/jit/stacktrace.c (stacktrace_create): Returns NULL if there is no
[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 7631 2007-04-02 20:04:22Z michi $
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
671    dump memory.
672
673    RETURN VALUE:
674       pointer to the stacktracebuffer, or
675       NULL if there is no stacktrace available for the
676       given thread.
677
678 *******************************************************************************/
679
680 stacktracebuffer *stacktrace_create(threadobject* thread)
681 {
682         stacktracebuffer *stb;
683         stackframeinfo   *sfi;
684         methodinfo       *m;
685         codeinfo         *code;
686         u1               *pv;
687         u1               *sp;
688         u4                framesize;
689         u1               *ra;
690         u1               *xpc;
691
692         /* prevent compiler warnings */
693
694         pv = NULL;
695         sp = NULL;
696         ra = NULL;
697
698         /* create a stacktracebuffer in dump memory */
699
700         stb = DNEW(stacktracebuffer);
701
702         stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
703         stb->used     = 0;
704         stb->entries  = DMNEW(stacktrace_entry, STACKTRACE_CAPACITY_DEFAULT);
705
706         /* The first element in the stackframe chain must always be a
707            native stackframeinfo (VMThrowable.fillInStackTrace is a native
708            function). */
709
710         /* We don't use the STACKFRAMEINFO macro here, as we have to use
711            the passed thread. */
712
713 #if defined(ENABLE_THREADS)
714         sfi = thread->_stackframeinfo;
715 #else
716         sfi = _no_threads_stackframeinfo;
717 #endif
718
719 #define PRINTMETHODS 0
720
721 #if PRINTMETHODS
722         printf("\n\nfillInStackTrace start:\n");
723         fflush(stdout);
724 #endif
725
726         /* Loop while we have a method pointer (asm_calljavafunction has
727            NULL) or there is a stackframeinfo in the chain. */
728
729         m = NULL;
730
731         while ((m != NULL) || (sfi != NULL)) {
732                 /* m == NULL should only happen for the first time and inline
733                    stackframe infos, like from the exception stubs or the
734                    patcher wrapper. */
735
736                 if (m == NULL) {
737                         /* for native stub stackframe infos, pv is always NULL */
738
739                         if (sfi->pv == NULL) {
740                                 /* get methodinfo, sp and ra from the current stackframe info */
741
742                                 m  = sfi->method;
743                                 sp = sfi->sp;           /* sp of parent Java function         */
744                                 ra = sfi->ra;
745
746                                 if (m)
747                                         stacktrace_add_entry(stb, m, 0);
748
749 #if PRINTMETHODS
750                                 printf("ra=%p sp=%p, ", ra, sp);
751                                 method_print(m);
752                                 printf(": native stub\n");
753                                 fflush(stdout);
754 #endif
755                                 /* This is an native stub stackframe info, so we can
756                                    get the parent pv from the return address
757                                    (ICMD_INVOKE*). */
758
759 #if defined(ENABLE_INTRP)
760                                 if (opt_intrp)
761                                         pv = codegen_get_pv_from_pc(ra);
762                                 else
763 #endif
764                                         {
765 #if defined(ENABLE_JIT)
766                                                 pv = md_codegen_get_pv_from_pc(ra);
767 #endif
768                                         }
769
770                                 /* get methodinfo pointer from parent data segment */
771
772                                 code = *((codeinfo **) (pv + CodeinfoPointer));
773
774                                 /* For asm_vm_call_method the codeinfo pointer is
775                                    NULL. */
776
777                                 m = (code == NULL) ? NULL : code->m;
778
779                         } else {
780                                 /* Inline stackframe infos are special: they have a
781                                    xpc of the actual exception position and the return
782                                    address saved since an inline stackframe info can
783                                    also be in a leaf method (no return address saved
784                                    on stack!!!).  ATTENTION: This one is also for
785                                    hardware exceptions!!! */
786
787                                 /* get methodinfo, sp and ra from the current stackframe info */
788
789                                 m   = sfi->method;      /* m == NULL                          */
790                                 pv  = sfi->pv;          /* pv of parent Java function         */
791                                 sp  = sfi->sp;          /* sp of parent Java function         */
792                                 ra  = sfi->ra;          /* ra of parent Java function         */
793                                 xpc = sfi->xpc;         /* actual exception position          */
794
795 #if PRINTMETHODS
796                                 printf("ra=%p sp=%p, ", ra, sp);
797                                 printf("NULL: inline stub\n");
798                                 fflush(stdout);
799 #endif
800
801                                 /* get methodinfo from current Java method */
802
803                                 code = *((codeinfo **) (pv + CodeinfoPointer));
804
805                                 /* For asm_vm_call_method the codeinfo pointer is
806                                    NULL. */
807
808                                 m = (code == NULL) ? NULL : code->m;
809
810                                 /* if m == NULL, this is a asm_calljavafunction call */
811
812                                 if (m != NULL) {
813 #if PRINTMETHODS
814                                         printf("ra=%p sp=%p, ", ra, sp);
815                                         method_print(m);
816                                         printf(": inline stub parent");
817                                         fflush(stdout);
818 #endif
819
820 #if defined(ENABLE_INTRP)
821                                         if (!opt_intrp) {
822 #endif
823
824                                         /* add the method to the stacktrace */
825
826                                         stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) xpc));
827
828                                         /* get the current stack frame size */
829
830                                         framesize = *((u4 *) (pv + FrameSize));
831
832 #if PRINTMETHODS
833                                         printf(", framesize=%d\n", framesize);
834                                         fflush(stdout);
835 #endif
836
837                                         /* Set stack pointer to stackframe of parent Java
838                                            function of the current Java function. */
839
840 #if defined(__I386__) || defined (__X86_64__)
841                                         sp += framesize + SIZEOF_VOID_P;
842 #elif defined(__SPARC_64__)
843                                         sp = md_get_framepointer(sp);
844 #else
845                                         sp += framesize;
846 #endif
847
848                                         /* get data segment and methodinfo pointer from
849                                            parent method */
850
851 #if defined(ENABLE_JIT)
852                                         pv = md_codegen_get_pv_from_pc(ra);
853 #endif
854
855                                         code = *((codeinfo **) (pv + CodeinfoPointer));
856
857                                         /* For asm_vm_call_method the codeinfo pointer is
858                                            NULL. */
859
860                                         m = (code == NULL) ? NULL : code->m;
861
862 #if defined(ENABLE_INTRP)
863                                         }
864 #endif
865                                 }
866 #if PRINTMETHODS
867                                 else {
868                                         printf("ra=%p sp=%p, ", ra, sp);
869                                         printf("asm_calljavafunction\n");
870                                         fflush(stdout);
871                                 }
872 #endif
873                         }
874
875                         /* get previous stackframeinfo in the chain */
876
877                         sfi = sfi->prev;
878
879                 } else {
880 #if PRINTMETHODS
881                         printf("ra=%p sp=%p, ", ra, sp);
882                         method_print(m);
883                         printf(": JIT");
884                         fflush(stdout);
885 #endif
886
887                         /* JIT method found, add it to the stacktrace (we subtract
888                            1 from the return address since it points the the
889                            instruction after call). */
890
891                         stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1);
892
893                         /* get the current stack frame size */
894
895                         framesize = *((u4 *) (pv + FrameSize));
896
897 #if PRINTMETHODS
898                         printf(", framesize=%d\n", framesize);
899                         fflush(stdout);
900 #endif
901
902                         /* get return address of current stack frame */
903
904 #if defined(ENABLE_JIT)
905 # if defined(ENABLE_INTRP)
906                         if (opt_intrp)
907                                 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
908                         else
909 # endif
910                                 ra = md_stacktrace_get_returnaddress(sp, framesize);
911 #else
912                         ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
913 #endif
914
915                         /* get data segment and methodinfo pointer from parent method */
916
917 #if defined(ENABLE_INTRP)
918                         if (opt_intrp)
919                                 pv = codegen_get_pv_from_pc(ra);
920                         else
921 #endif
922                                 {
923 #if defined(ENABLE_JIT)
924 # if defined(__SPARC_64__)
925                                         sp = md_get_framepointer(sp);
926                                         pv = md_get_pv_from_stackframe(sp);
927 # else
928                                         pv = md_codegen_get_pv_from_pc(ra);
929 # endif
930 #endif
931                                 }
932
933                         code = *((codeinfo **) (pv + CodeinfoPointer));
934
935                         /* For asm_vm_call_method the codeinfo pointer is NULL. */
936
937                         m = (code == NULL) ? NULL : code->m;
938
939                         /* walk the stack */
940
941 #if defined(ENABLE_INTRP)
942                         if (opt_intrp)
943                                 sp = *(u1 **) (sp - framesize);
944                         else
945 #endif
946                                 {
947 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
948                                         sp += framesize + SIZEOF_VOID_P;
949 #elif defined(__SPARC_64__)
950                                         /* already has the new sp */
951 #else
952                                         sp += framesize;
953 #endif
954                                 }
955                 }
956         }
957
958         /* return the stacktracebuffer */
959
960         if (stb->used == 0)
961                 return NULL;
962         else
963                 return stb;
964 }
965
966
967 /* stacktrace_fillInStackTrace *************************************************
968
969    Generate a stacktrace from the current thread for
970    java.lang.VMThrowable.fillInStackTrace.
971
972 *******************************************************************************/
973
974 stacktracecontainer *stacktrace_fillInStackTrace(void)
975 {
976         stacktracebuffer    *stb;
977         stacktracecontainer *gcstc;
978         s4                   gcstc_size;
979         s4                   dumpsize;
980         CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
981
982         /* mark start of dump memory area */
983
984         dumpsize = dump_size();
985
986         /* create a stacktrace from the current thread */
987
988         stb = stacktrace_create(THREADOBJECT);
989         if (!stb)
990                 goto return_NULL;
991
992         /* allocate memory from the GC heap and copy the stacktrace buffer */
993         /* ATTENTION: use stacktracecontainer for this and make it look like
994        an array */
995
996         gcstc_size = sizeof(stacktracebuffer) +
997                      sizeof(stacktrace_entry) * stb->used;
998         gcstc = (stacktracecontainer *) builtin_newarray_byte(gcstc_size);
999
1000         if (gcstc == NULL)
1001                 goto return_NULL;
1002
1003         gcstc->stb.capacity = stb->capacity;
1004         gcstc->stb.used     = stb->used;
1005         gcstc->stb.entries  = gcstc->data;
1006
1007         MCOPY(gcstc->data, stb->entries, stacktrace_entry, stb->used);
1008
1009         /* release dump memory */
1010
1011         dump_release(dumpsize);
1012
1013         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
1014                                                                    stacktrace_overhead)
1015         return gcstc;
1016
1017 return_NULL:
1018         dump_release(dumpsize);
1019
1020         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
1021                                                                    stacktrace_overhead)
1022
1023         return NULL;
1024 }
1025
1026
1027 /* stacktrace_getClassContext **************************************************
1028
1029    Creates a Class context array.
1030
1031    RETURN VALUE:
1032       the array of java.lang.Class objects, or
1033           NULL if an exception has been thrown
1034
1035 *******************************************************************************/
1036
1037 java_objectarray *stacktrace_getClassContext(void)
1038 {
1039         stacktracebuffer  *stb;
1040         stacktrace_entry  *ste;
1041         java_objectarray  *oa;
1042         s4                 oalength;
1043         s4                 i;
1044         s4                 dumpsize;
1045         CYCLES_STATS_DECLARE_AND_START
1046
1047         /* mark start of dump memory area */
1048
1049         dumpsize = dump_size();
1050
1051         /* create a stacktrace for the current thread */
1052
1053         stb = stacktrace_create(THREADOBJECT);
1054         if (!stb)
1055                 goto return_NULL;
1056
1057         /* calculate the size of the Class array */
1058
1059         for (i = 0, oalength = 0; i < stb->used; i++)
1060                 if (stb->entries[i].method != NULL)
1061                         oalength++;
1062
1063         /* The first entry corresponds to the method whose implementation */
1064         /* calls stacktrace_getClassContext. We remove that entry.        */
1065
1066         ste = &(stb->entries[0]);
1067         ste++;
1068         oalength--;
1069
1070         /* allocate the Class array */
1071
1072         oa = builtin_anewarray(oalength, class_java_lang_Class);
1073         if (!oa)
1074                 goto return_NULL;
1075
1076         /* fill the Class array from the stacktracebuffer */
1077
1078         for(i = 0; i < oalength; i++, ste++) {
1079                 if (ste->method == NULL) {
1080                         i--;
1081                         continue;
1082                 }
1083
1084                 oa->data[i] = (java_objectheader *) ste->method->class;
1085         }
1086
1087         /* release dump memory */
1088
1089         dump_release(dumpsize);
1090
1091         CYCLES_STATS_END(stacktrace_getClassContext)
1092
1093         return oa;
1094
1095 return_NULL:
1096         dump_release(dumpsize);
1097
1098         CYCLES_STATS_END(stacktrace_getClassContext)
1099
1100         return NULL;
1101 }
1102
1103
1104 /* stacktrace_getCurrentClass **************************************************
1105
1106    Find the current class by walking the stack trace.
1107
1108    Quote from the JNI documentation:
1109          
1110    In the Java 2 Platform, FindClass locates the class loader
1111    associated with the current native method.  If the native code
1112    belongs to a system class, no class loader will be
1113    involved. Otherwise, the proper class loader will be invoked to
1114    load and link the named class. When FindClass is called through the
1115    Invocation Interface, there is no current native method or its
1116    associated class loader. In that case, the result of
1117    ClassLoader.getBaseClassLoader is used."
1118
1119 *******************************************************************************/
1120
1121 #if defined(ENABLE_JAVASE)
1122 classinfo *stacktrace_getCurrentClass(void)
1123 {
1124         stacktracebuffer  *stb;
1125         stacktrace_entry  *ste;
1126         methodinfo        *m;
1127         s4                 i;
1128         s4                 dumpsize;
1129         CYCLES_STATS_DECLARE_AND_START
1130
1131         /* mark start of dump memory area */
1132
1133         dumpsize = dump_size();
1134
1135         /* create a stacktrace for the current thread */
1136
1137         stb = stacktrace_create(THREADOBJECT);
1138         if (!stb)
1139                 goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
1140
1141         /* iterate over all stacktrace entries and find the first suitable
1142            class */
1143
1144         for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
1145                 m = ste->method;
1146
1147                 if (m == NULL)
1148                         continue;
1149
1150                 if (m->class == class_java_security_PrivilegedAction)
1151                         goto return_NULL;
1152
1153                 if (m->class != NULL) {
1154                         dump_release(dumpsize);
1155
1156                         CYCLES_STATS_END(stacktrace_getCurrentClass)
1157
1158                         return m->class;
1159                 }
1160         }
1161
1162         /* no Java method found on the stack */
1163
1164 return_NULL:
1165         dump_release(dumpsize);
1166
1167         CYCLES_STATS_END(stacktrace_getCurrentClass)
1168
1169         return NULL;
1170 }
1171 #endif /* ENABLE_JAVASE */
1172
1173
1174 /* stacktrace_getStack *********************************************************
1175
1176    Create a 2-dimensional array for java.security.VMAccessControler.
1177
1178    RETURN VALUE:
1179       the arrary, or
1180           NULL if an exception has been thrown
1181
1182 *******************************************************************************/
1183
1184 #if defined(ENABLE_JAVASE)
1185 java_objectarray *stacktrace_getStack(void)
1186 {
1187         stacktracebuffer  *stb;
1188         stacktrace_entry  *ste;
1189         java_objectarray  *oa;
1190         java_objectarray  *classes;
1191         java_objectarray  *methodnames;
1192         classinfo         *c;
1193         java_objectheader *string;
1194         s4                 i;
1195         s4                 dumpsize;
1196         CYCLES_STATS_DECLARE_AND_START
1197
1198         /* mark start of dump memory area */
1199
1200         dumpsize = dump_size();
1201
1202         /* create a stacktrace for the current thread */
1203
1204         stb = stacktrace_create(THREADOBJECT);
1205
1206         if (stb == NULL)
1207                 goto return_NULL;
1208
1209         /* get the first stacktrace entry */
1210
1211         ste = &(stb->entries[0]);
1212
1213         /* allocate all required arrays */
1214
1215         oa = builtin_anewarray(2, arrayclass_java_lang_Object);
1216
1217         if (oa == NULL)
1218                 goto return_NULL;
1219
1220         classes = builtin_anewarray(stb->used, class_java_lang_Class);
1221
1222         if (classes == NULL)
1223                 goto return_NULL;
1224
1225         methodnames = builtin_anewarray(stb->used, class_java_lang_String);
1226
1227         if (methodnames == NULL)
1228                 goto return_NULL;
1229
1230         /* set up the 2-dimensional array */
1231
1232         oa->data[0] = (java_objectheader *) classes;
1233         oa->data[1] = (java_objectheader *) methodnames;
1234
1235         /* iterate over all stacktrace entries */
1236
1237         for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
1238                 c = ste->method->class;
1239
1240                 classes->data[i] = (java_objectheader *) c;
1241
1242                 string = javastring_new(ste->method->name);
1243
1244                 if (string == NULL)
1245                         goto return_NULL;
1246
1247                 methodnames->data[i] = string;
1248         }
1249
1250         /* return the 2-dimensional array */
1251
1252         dump_release(dumpsize);
1253
1254         CYCLES_STATS_END(stacktrace_getStack)
1255
1256         return oa;
1257
1258 return_NULL:
1259         dump_release(dumpsize);
1260
1261         CYCLES_STATS_END(stacktrace_getStack)
1262
1263         return NULL;
1264 }
1265 #endif /* ENABLE_JAVASE */
1266
1267
1268 /* stacktrace_print_trace_from_buffer ******************************************
1269
1270    Print the stacktrace of a given stacktracebuffer with CACAO intern
1271    methods (no Java help). This method is used by
1272    stacktrace_dump_trace and builtin_trace_exception.
1273
1274 *******************************************************************************/
1275
1276 void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
1277 {
1278         stacktrace_entry *ste;
1279         methodinfo       *m;
1280         s4                i;
1281
1282         ste = &(stb->entries[0]);
1283
1284         for (i = 0; i < stb->used; i++, ste++) {
1285                 m = ste->method;
1286
1287                 printf("\tat ");
1288                 utf_display_printable_ascii_classname(m->class->name);
1289                 printf(".");
1290                 utf_display_printable_ascii(m->name);
1291                 utf_display_printable_ascii(m->descriptor);
1292
1293                 if (m->flags & ACC_NATIVE) {
1294                         puts("(Native Method)");
1295
1296                 } else {
1297                         printf("(");
1298                         utf_display_printable_ascii(m->class->sourcefile);
1299                         printf(":%d)\n", (u4) ste->linenumber);
1300                 }
1301         }
1302
1303         /* just to be sure */
1304
1305         fflush(stdout);
1306 }
1307
1308
1309 /* stacktrace_dump_trace *******************************************************
1310
1311    This method is call from signal_handler_sigusr1 to dump the
1312    stacktrace of the current thread to stdout.
1313
1314 *******************************************************************************/
1315
1316 void stacktrace_dump_trace(threadobject *thread)
1317 {
1318         stacktracebuffer *stb;
1319         s4                dumpsize;
1320
1321         /* mark start of dump memory area */
1322
1323         dumpsize = dump_size();
1324
1325         /* create a stacktrace for the current thread */
1326
1327         stb = stacktrace_create(thread);
1328
1329         /* print stacktrace */
1330
1331         if (stb != NULL)
1332                 stacktrace_print_trace_from_buffer(stb);
1333         else {
1334                 puts("\t<<No stacktrace available>>");
1335                 fflush(stdout);
1336         }
1337
1338         dump_release(dumpsize);
1339 }
1340
1341
1342 /* stacktrace_print_trace ******************************************************
1343
1344    Print the stacktrace of a given exception. More or less a wrapper
1345    to stacktrace_print_trace_from_buffer.
1346
1347 *******************************************************************************/
1348
1349 void stacktrace_print_trace(java_objectheader *xptr)
1350 {
1351         java_lang_Throwable   *t;
1352 #if defined(WITH_CLASSPATH_GNU)
1353         java_lang_VMThrowable *vmt;
1354 #endif
1355         stacktracecontainer   *stc;
1356         stacktracebuffer      *stb;
1357
1358         t = (java_lang_Throwable *) xptr;
1359
1360         if (t == NULL)
1361                 return;
1362
1363         /* now print the stacktrace */
1364
1365 #if defined(WITH_CLASSPATH_GNU)
1366         vmt = t->vmState;
1367         stc = (stacktracecontainer *) vmt->vmData;
1368         stb = &(stc->stb);
1369 #elif defined(WITH_CLASSPATH_CLDC1_1)
1370         stc = (stacktracecontainer *) t->backtrace;
1371         stb = &(stc->stb);
1372 #endif
1373
1374         stacktrace_print_trace_from_buffer(stb);
1375 }
1376
1377
1378 #if defined(ENABLE_CYCLES_STATS)
1379 void stacktrace_print_cycles_stats(FILE *file)
1380 {
1381         CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
1382         CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
1383         CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
1384         CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
1385         CYCLES_STATS_PRINT(stacktrace_getStack        ,file);
1386 }
1387 #endif
1388
1389
1390 /*
1391  * These are local overrides for various environment variables in Emacs.
1392  * Please do not remove this and leave it at the end of the file, where
1393  * Emacs will automagically detect them.
1394  * ---------------------------------------------------------------------
1395  * Local variables:
1396  * mode: c
1397  * indent-tabs-mode: t
1398  * c-basic-offset: 4
1399  * tab-width: 4
1400  * End:
1401  * vim:noexpandtab:sw=4:ts=4:
1402  */