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