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