* callingMethodCollector: Return [1] element since it's called from a
[cacao.git] / src / vm / jit / stacktrace.c
1 /* src/vm/jit/stacktrace.c - machine independet stacktrace system
2
3    Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4    R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5    C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6    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., 59 Temple Place - Suite 330, Boston, MA
23    02111-1307, USA.
24
25    Contact: cacao@complang.tuwien.ac.at
26
27    Authors: Joseph Wenninger
28
29    Changes: Christian Thalinger
30
31    $Id: stacktrace.c 3456 2005-10-19 22:06:23Z twisti $
32
33 */
34
35
36 #include <assert.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include "config.h"
41
42 #include "mm/boehm.h"
43 #include "native/native.h"
44
45 #include "vm/global.h"                   /* required here for native includes */
46 #include "native/include/java_lang_ClassLoader.h"
47
48 #include "toolbox/logging.h"
49 #include "vm/builtin.h"
50 #include "vm/class.h"
51 #include "vm/exceptions.h"
52 #include "vm/loader.h"
53 #include "vm/options.h"
54 #include "vm/stringlocal.h"
55 #include "vm/tables.h"
56 #include "vm/jit/asmpart.h"
57 #include "vm/jit/codegen.inc.h"
58 #include "vm/jit/methodheader.h"
59
60
61 /* lineNumberTableEntry *******************************************************/
62
63 /* Keep the type of line the same as the pointer type, otherwise we run into  */
64 /* alignment troubles (like on MIPS64).                                       */
65
66 typedef struct lineNumberTableEntry {
67         ptrint  line;
68         u1     *pc;
69 } lineNumberTableEntry;
70
71
72 typedef struct lineNumberTableEntryInlineBegin {
73         /* this should have the same layout and size as the lineNumberTableEntry */
74         ptrint      lineNrOuter;
75         methodinfo *method;
76 } lineNumberTableEntryInlineBegin;
77
78
79 typedef bool(*CacaoStackTraceCollector)(void **, stackTraceBuffer*);
80
81 #define BLOCK_INITIALSIZE 40
82 #define BLOCK_SIZEINCREMENT 40
83
84
85 /* global variables ***********************************************************/
86
87 #if defined(USE_THREADS)
88 #define STACKFRAMEINFO    (stackframeinfo **) (&THREADINFO->_stackframeinfo)
89 #else
90 THREADSPECIFIC stackframeinfo *_no_threads_stackframeinfo = NULL;
91
92 #define STACKFRAMEINFO    (&_no_threads_stackframeinfo)
93 #endif
94
95
96 /* stacktrace_create_stackframeinfo ********************************************
97
98    Creates an stackframe info structure for inline code in the
99    interpreter.
100
101 *******************************************************************************/
102
103 #if defined(ENABLE_INTRP)
104 void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv,
105                                                                           u1 *sp, functionptr ra)
106 {
107         stackframeinfo **psfi;
108         methodinfo      *m;
109
110         /* get current stackframe info pointer */
111
112         psfi = STACKFRAMEINFO;
113
114         /* if we don't have pv handy */
115
116         if (pv == NULL)
117                 pv = (u1 *) (ptrint) codegen_findmethod(ra);
118
119         /* get methodinfo pointer from data segment */
120
121         m = *((methodinfo **) (pv + MethodPointer));
122
123         /* fill new stackframe info structure */
124
125         sfi->prev = *psfi;
126         sfi->method = m;
127         sfi->pv = pv;
128         sfi->sp = sp;
129         sfi->ra = ra;
130
131         /* xpc is the same as ra, but is required in fillInStackTrace */
132
133         sfi->xpc = ra;
134
135         /* store new stackframe info pointer */
136
137         *psfi = sfi;
138 }
139 #endif /* defined(ENABLE_INTRP) */
140
141 /* stacktrace_create_inline_stackframeinfo *************************************
142
143    Creates an stackframe info structure for an inline exception stub.
144
145 *******************************************************************************/
146
147 void stacktrace_create_inline_stackframeinfo(stackframeinfo *sfi, u1 *pv,
148                                                                                          u1 *sp, functionptr ra,
149                                                                                          functionptr xpc)
150 {
151         stackframeinfo **psfi;
152
153         /* get current stackframe info pointer */
154
155         psfi = STACKFRAMEINFO;
156
157 #if defined(ENABLE_INTRP)
158         if (opt_intrp) {
159                 /* if we don't have pv handy */
160
161                 if (pv == NULL)
162                         pv = (u1 *) (ptrint) codegen_findmethod(ra);
163
164         }
165 #endif
166
167         /* fill new stackframe info structure */
168
169         sfi->prev = *psfi;
170         sfi->method = NULL;
171         sfi->pv = pv;
172         sfi->sp = sp;
173         sfi->ra = ra;
174         sfi->xpc = xpc;
175
176         /* store new stackframe info pointer */
177
178         *psfi = sfi;
179 }
180
181
182 /* stacktrace_create_extern_stackframeinfo *************************************
183
184    Creates an stackframe info structure for an extern exception
185    (hardware or assembler).
186
187 *******************************************************************************/
188
189 void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
190                                                                                          u1 *sp, functionptr ra,
191                                                                                          functionptr xpc)
192 {
193         stackframeinfo **psfi;
194 #if !defined(__I386__) && !defined(__X86_64__)
195         bool             isleafmethod;
196 #endif
197         s4               framesize;
198
199         /* get current stackframe info pointer */
200
201         psfi = STACKFRAMEINFO;
202
203         /* sometimes we don't have pv handy (e.g. in asmpart.S:
204        L_asm_call_jit_compiler_exception or in the interpreter). */
205
206         if (pv == NULL)
207                 pv = (u1 *) (ptrint) codegen_findmethod(ra);
208
209 #if defined(ENABLE_INTRP)
210         /* When using the interpreter, we pass RA to the function. */
211
212         if (!opt_intrp) {
213 #endif
214 # if defined(__I386__) || defined(__X86_64__)
215                 /* On i386 and x86_64 we always have to get the return address
216                    from the stack. */
217
218                 framesize = *((u4 *) (pv + FrameSize));
219
220                 ra = md_stacktrace_get_returnaddress(sp, framesize);
221 # else
222                 /* If the method is a non-leaf function, we need to get the return
223                    address from the stack. For leaf functions the return address
224                    is set correctly. This makes the assembler and the signal
225                    handler code simpler. */
226
227                 isleafmethod = *((s4 *) (pv + IsLeaf));
228
229                 if (!isleafmethod) {
230                         framesize = *((u4 *) (pv + FrameSize));
231
232                         ra = md_stacktrace_get_returnaddress(sp, framesize);
233                 }
234 # endif
235 #if defined(ENABLE_INTRP)
236         }
237 #endif
238
239         /* fill new stackframe info structure */
240
241         sfi->prev = *psfi;
242         sfi->method = NULL;
243         sfi->pv = pv;
244         sfi->sp = sp;
245         sfi->ra = ra;
246         sfi->xpc = xpc;
247
248         /* store new stackframe info pointer */
249
250         *psfi = sfi;
251 }
252
253
254 /* stacktrace_create_native_stackframeinfo *************************************
255
256    Creates a stackframe info structure for a native stub.
257
258 *******************************************************************************/
259
260 void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv,
261                                                                                          u1 *sp, functionptr ra)
262 {
263         stackframeinfo **psfi;
264         methodinfo      *m;
265
266         /* get methodinfo pointer from data segment */
267
268         m = *((methodinfo **) (pv + MethodPointer));
269
270         /* get current stackframe info pointer */
271
272         psfi = STACKFRAMEINFO;
273
274         /* fill new stackframe info structure */
275
276         sfi->prev = *psfi;
277         sfi->method = m;
278         sfi->pv = NULL;
279         sfi->sp = sp;
280         sfi->ra = ra;
281         sfi->xpc = NULL;
282
283         /* store new stackframe info pointer */
284
285         *psfi = sfi;
286 }
287
288
289 /* stacktrace_remove_stackframeinfo ********************************************
290
291    XXX
292
293 *******************************************************************************/
294
295 void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
296 {
297         stackframeinfo **psfi;
298
299         /* get current stackframe info pointer */
300
301         psfi = STACKFRAMEINFO;
302
303         /* restore the old pointer */
304
305         *psfi = sfi->prev;
306 }
307
308
309 /* stacktrace_inline_arithmeticexception ***************************************
310
311    Creates an ArithemticException for inline stub.
312
313 *******************************************************************************/
314
315 java_objectheader *stacktrace_inline_arithmeticexception(u1 *pv, u1 *sp,
316                                                                                                                  functionptr ra,
317                                                                                                                  functionptr xpc)
318 {
319         stackframeinfo     sfi;
320         java_objectheader *o;
321
322         /* create stackframeinfo */
323
324         stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
325
326         /* create exception */
327
328         o = new_arithmeticexception();
329
330         /* remove stackframeinfo */
331
332         stacktrace_remove_stackframeinfo(&sfi);
333
334         return o;
335 }
336
337
338 /* stacktrace_inline_arrayindexoutofboundsexception ****************************
339
340    Creates an ArrayIndexOutOfBoundsException for inline stub.
341
342 *******************************************************************************/
343
344 java_objectheader *stacktrace_inline_arrayindexoutofboundsexception(u1 *pv,
345                                                                                                                                         u1 *sp,
346                                                                                                                                         functionptr ra,
347                                                                                                                                         functionptr xpc,
348                                                                                                                                         s4 index)
349 {
350         stackframeinfo     sfi;
351         java_objectheader *o;
352
353         /* create stackframeinfo */
354
355         stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
356
357         /* create exception */
358
359         o = new_arrayindexoutofboundsexception(index);
360
361         /* remove stackframeinfo */
362
363         stacktrace_remove_stackframeinfo(&sfi);
364
365         return o;
366 }
367
368
369 /* stacktrace_inline_arraystoreexception ***************************************
370
371    Creates an ArrayStoreException for inline stub.
372
373 *******************************************************************************/
374
375 java_objectheader *stacktrace_inline_arraystoreexception(u1 *pv, u1 *sp,
376                                                                                                                  functionptr ra,
377                                                                                                                  functionptr xpc)
378 {
379         stackframeinfo     sfi;
380         java_objectheader *o;
381
382         /* create stackframeinfo */
383
384         stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
385
386         /* create exception */
387
388         o = new_arraystoreexception();
389
390         /* remove stackframeinfo */
391
392         stacktrace_remove_stackframeinfo(&sfi);
393
394         return o;
395 }
396
397
398 /* stacktrace_inline_classcastexception ****************************************
399
400    Creates an ClassCastException for inline stub.
401
402 *******************************************************************************/
403
404 java_objectheader *stacktrace_inline_classcastexception(u1 *pv, u1 *sp,
405                                                                                                                 functionptr ra,
406                                                                                                                 functionptr xpc)
407 {
408         stackframeinfo     sfi;
409         java_objectheader *o;
410
411         /* create stackframeinfo */
412
413         stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
414
415         /* create exception */
416
417         o = new_classcastexception();
418
419         /* remove stackframeinfo */
420
421         stacktrace_remove_stackframeinfo(&sfi);
422
423         return o;
424 }
425
426
427 /* stacktrace_inline_nullpointerexception **************************************
428
429    Creates an NullPointerException for inline stub.
430
431 *******************************************************************************/
432
433 java_objectheader *stacktrace_inline_nullpointerexception(u1 *pv, u1 *sp,
434                                                                                                                   functionptr ra,
435                                                                                                                   functionptr xpc)
436 {
437         stackframeinfo     sfi;
438         java_objectheader *o;
439
440         /* create stackframeinfo */
441
442         stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
443
444         /* create exception */
445
446         o = new_nullpointerexception();
447
448         /* remove stackframeinfo */
449
450         stacktrace_remove_stackframeinfo(&sfi);
451
452         return o;
453 }
454
455
456 /* stacktrace_hardware_arithmeticexception *************************************
457
458    Creates an ArithemticException for inline stub.
459
460 *******************************************************************************/
461
462 java_objectheader *stacktrace_hardware_arithmeticexception(u1 *pv, u1 *sp,
463                                                                                                                    functionptr ra,
464                                                                                                                    functionptr xpc)
465 {
466         stackframeinfo     sfi;
467         java_objectheader *o;
468
469         /* create stackframeinfo */
470
471         stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
472
473         /* create exception */
474
475         o = new_arithmeticexception();
476
477         /* remove stackframeinfo */
478
479         stacktrace_remove_stackframeinfo(&sfi);
480
481         return o;
482 }
483
484
485 /* stacktrace_hardware_nullpointerexception ************************************
486
487    Creates an NullPointerException for the SIGSEGV signal handler.
488
489 *******************************************************************************/
490
491 java_objectheader *stacktrace_hardware_nullpointerexception(u1 *pv, u1 *sp,
492                                                                                                                         functionptr ra,
493                                                                                                                         functionptr xpc)
494 {
495         stackframeinfo     sfi;
496         java_objectheader *o;
497
498         /* create stackframeinfo */
499
500         stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
501
502         /* create exception */
503
504         o = new_nullpointerexception();
505
506         /* remove stackframeinfo */
507
508         stacktrace_remove_stackframeinfo(&sfi);
509
510         return o;
511 }
512
513
514 /* stacktrace_inline_fillInStackTrace ******************************************
515
516    Fills in the correct stacktrace into an existing exception object
517    (this one is for inline exception stubs).
518
519 *******************************************************************************/
520
521 java_objectheader *stacktrace_inline_fillInStackTrace(u1 *pv, u1 *sp,
522                                                                                                           functionptr ra,
523                                                                                                           functionptr xpc)
524 {
525         stackframeinfo     sfi;
526         java_objectheader *o;
527         methodinfo        *m;
528
529         /* create stackframeinfo */
530
531         stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
532
533         /* get exception */
534
535         o = *exceptionptr;
536
537         /* clear exception */
538
539         *exceptionptr = NULL;
540
541         /* resolve methodinfo pointer from exception object */
542
543         m = class_resolvemethod(o->vftbl->class,
544                                                         utf_fillInStackTrace,
545                                                         utf_void__java_lang_Throwable);
546
547         /* call function */
548
549         asm_calljavafunction(m, o, NULL, NULL, NULL);
550
551         /* remove stackframeinfo */
552
553         stacktrace_remove_stackframeinfo(&sfi);
554
555         return o;
556 }
557
558
559 /* addEntry ********************************************************************
560
561    XXX
562
563 *******************************************************************************/
564
565 static void addEntry(stackTraceBuffer *buffer, methodinfo *method, u2 line)
566 {
567         if (buffer->size > buffer->full) {
568                 stacktraceelement *tmp = &(buffer->start[buffer->full]);
569
570                 tmp->method = method;
571                 tmp->linenumber = line;
572                 buffer->full = buffer->full + 1;
573
574         } else {
575                 stacktraceelement *newBuffer;
576
577                 newBuffer =
578                         (stacktraceelement *) malloc((buffer->size + BLOCK_SIZEINCREMENT) *
579                                                                                  sizeof(stacktraceelement));
580
581                 if (newBuffer == 0) {
582                         log_text("OOM during stacktrace creation");
583                         assert(0);
584                 }
585
586                 memcpy(newBuffer, buffer->start, buffer->size * sizeof(stacktraceelement));
587                 if (buffer->needsFree)
588                         free(buffer->start);
589
590                 buffer->start = newBuffer;
591                 buffer->size = buffer->size + BLOCK_SIZEINCREMENT;
592                 buffer->needsFree = 1;
593
594                 addEntry(buffer, method, line);
595         }
596 }
597
598
599 /* stacktrace_fillInStackTrace_methodRecursive *********************************
600
601    XXX
602
603 *******************************************************************************/
604
605 static bool stacktrace_fillInStackTrace_methodRecursive(stackTraceBuffer *buffer,
606                                                                                                                 methodinfo *m,
607                                                                                                                 lineNumberTableEntry *lntentry,
608                                                                                                                 s4 lntsize,
609                                                                                                                 u1 *pc)
610 {
611 #if 0
612         lineNumberTableEntryInlineBegin *lntinline;
613 #endif
614
615         /* find the line number for the specified pc (going backwards) */
616
617         for (; lntsize > 0; lntsize--, lntentry--) {
618                 /* did we reach the current line? */
619
620                 if (pc >= lntentry->pc) {
621                         /* check for special inline entries */
622
623                         switch (lntentry->line) {
624 #if 0
625                         /* XXX TWISTI we have to think about this inline stuff again */
626
627                         case -1: /* begin of inlined method */
628                                 lntinline = (lineNumberTableEntryInlineBegin *) (--lntentry);
629                                 lntentry++;
630                                 lntsize--; lntsize--;
631                                 if (stacktrace_fillInStackTrace_methodRecursive(buffer,
632                                                                                                                                 ilStart->method,
633                                                                                                                                 ent,
634                                                                                                                                 &ent,
635                                                                                                                                 &ahead,
636                                                                                                                                 pc)) {
637                                         addEntry(buffer, m, ilStart->lineNrOuter);
638
639                                         return true;
640                                 }
641                                 break;
642
643                         case -2: /* end of inlined method */
644                                 *entry = ent;
645                                 *entriesAhead = ahead;
646                                 return false;
647                                 break;
648 #endif
649
650                         default:
651                                 addEntry(buffer, m, lntentry->line);
652                                 return true;
653                         }
654                 }
655         }
656
657         /* check if we are before the actual JIT code */
658
659         if ((ptrint) pc < (ptrint) m->entrypoint) {
660                 dolog("Current pc before start of code: %p < %p", pc, m->entrypoint);
661                 assert(0);
662         }
663
664         /* otherwise just add line 0 */
665
666         addEntry(buffer, m, 0);
667
668         return true;
669 }
670
671
672 /* stacktrace_fillInStackTrace_method ******************************************
673
674    XXX
675
676 *******************************************************************************/
677
678 static void stacktrace_fillInStackTrace_method(stackTraceBuffer *buffer,
679                                                                                            methodinfo *method, u1 *pv,
680                                                                                            u1 *pc)
681 {
682         ptrint                lntsize;      /* size of line number table          */
683         u1                   *lntstart;     /* start of line number table         */
684         lineNumberTableEntry *lntentry;     /* points to last entry in the table  */
685
686         /* get size of line number table */
687
688         lntsize  = *((ptrint *) (pv + LineNumberTableSize));
689         lntstart = *((u1 **)    (pv + LineNumberTableStart));
690
691         /* subtract the size of the line number entry of the structure, since the */
692         /* line number table start points to the pc */
693
694         lntentry = (lineNumberTableEntry *) (lntstart - SIZEOF_VOID_P);
695
696         if (lntsize == 0) {
697                 /* this happens when an exception is thrown in the native stub */
698
699                 addEntry(buffer, method, 0);
700
701         } else {
702                 if (!stacktrace_fillInStackTrace_methodRecursive(buffer,
703                                                                                                                  method,
704                                                                                                                  lntentry,
705                                                                                                                  lntsize,
706                                                                                                                  pc)) {
707                         log_text("Trace point not found in suspected method");
708                         assert(0);
709                 }
710         }
711 }
712
713
714 /* cacao_stacktrace_fillInStackTrace *******************************************
715
716    XXX
717
718 *******************************************************************************/
719
720 static bool cacao_stacktrace_fillInStackTrace(void **target,
721                                                                                           CacaoStackTraceCollector coll)
722 {
723         stacktraceelement primaryBlock[BLOCK_INITIALSIZE*sizeof(stacktraceelement)];
724         stackTraceBuffer  buffer;
725         stackframeinfo   *sfi;
726         methodinfo       *m;
727         u1               *pv;
728         u1               *sp;
729         u4                framesize;
730         functionptr       ra;
731         functionptr       xpc;
732         bool              result;
733
734         /* prevent compiler warnings */
735
736         pv = NULL;
737         sp = NULL;
738         ra = NULL;
739
740         /* In most cases this should be enough -> one malloc less. I don't think  */
741         /* temporary data should be allocated with the GC, only the result.       */
742
743         buffer.needsFree = 0;
744         buffer.start = primaryBlock;
745         buffer.size = BLOCK_INITIALSIZE; /*  *sizeof(stacktraceelement); */
746         buffer.full = 0;
747
748         /* the first element in the stackframe chain must always be a native      */
749         /* stackframeinfo (VMThrowable.fillInStackTrace is a native function)     */
750
751         sfi = *STACKFRAMEINFO;
752
753         if (!sfi) {
754                 *target = NULL;
755                 return true;
756         }
757
758 #define PRINTMETHODS 0
759
760 #if PRINTMETHODS
761         printf("\n\nfillInStackTrace start:\n");
762 #endif
763
764         /* loop while we have a method pointer (asm_calljavafunction has NULL) or */
765         /* there is a stackframeinfo in the chain                                 */
766
767         m = NULL;
768
769         while (m || sfi) {
770                 /* m == NULL should only happen for the first time and inline         */
771                 /* stackframe infos, like from the exception stubs or the patcher     */
772                 /* wrapper                                                            */
773
774                 if (m == NULL) {
775                         /* for native stub stackframe infos, pv is always NULL */
776
777                         if (sfi->pv == NULL) {
778                                 /* get methodinfo, sp and ra from the current stackframe info */
779
780                                 m  = sfi->method;
781                                 sp = sfi->sp;           /* sp of parent Java function         */
782                                 ra = sfi->ra;
783
784                                 if (m)
785                                         addEntry(&buffer, m, 0);
786
787 #if PRINTMETHODS
788                                 utf_display_classname(m->class->name);
789                                 printf(".");
790                                 utf_display(m->name);
791                                 utf_display(m->descriptor);
792                                 printf(": native stub\n");
793 #endif
794                                 /* this is an native stub stackframe info, so we can get the */
795                                 /* parent pv from the return address (ICMD_INVOKE*) */
796
797                                 pv = (u1 *) (ptrint) codegen_findmethod(ra);
798
799                                 /* get methodinfo pointer from parent data segment */
800
801                                 m = *((methodinfo **) (pv + MethodPointer));
802
803                         } else {
804                                 /* Inline stackframe infos are special: they have a xpc of    */
805                                 /* the actual exception position and the return address saved */
806                                 /* since an inline stackframe info can also be in a leaf      */
807                                 /* method (no return address saved on stack!!!).              */
808                                 /* ATTENTION: This one is also for hardware exceptions!!!     */
809
810                                 /* get methodinfo, sp and ra from the current stackframe info */
811
812                                 m   = sfi->method;      /* m == NULL                          */
813                                 pv  = sfi->pv;          /* pv of parent Java function         */
814                                 sp  = sfi->sp;          /* sp of parent Java function         */
815                                 ra  = sfi->ra;          /* ra of parent Java function         */
816                                 xpc = sfi->xpc;         /* actual exception position          */
817
818 #if PRINTMETHODS
819                                 printf("NULL: inline stub\n");
820 #endif
821
822                                 /* get methodinfo from current Java method */
823
824                                 m = *((methodinfo **) (pv + MethodPointer));
825
826                                 /* if m == NULL, this is a asm_calljavafunction call */
827
828                                 if (m != NULL) {
829 #if PRINTMETHODS
830                                         utf_display_classname(m->class->name);
831                                         printf(".");
832                                         utf_display(m->name);
833                                         utf_display(m->descriptor);
834                                         printf(": inline stub parent\n");
835 #endif
836
837 #if defined(ENABLE_INTRP)
838                                         if (!opt_intrp) {
839 #endif
840
841                                         /* add it to the stacktrace */
842
843                                         stacktrace_fillInStackTrace_method(&buffer, m, pv,
844                                                                                                            (u1 *) ((ptrint) xpc));
845
846                                         /* get the current stack frame size */
847
848                                         framesize = *((u4 *) (pv + FrameSize));
849
850                                         /* set stack pointer to stackframe of parent Java */
851                                         /* function of the current Java function */
852
853 #if defined(__I386__) || defined (__X86_64__)
854                                         sp += framesize + SIZEOF_VOID_P;
855 #else
856                                         sp += framesize;
857 #endif
858
859                                         /* get data segment and methodinfo pointer from parent */
860                                         /* method */
861
862                                         pv = (u1 *) (ptrint) codegen_findmethod(ra);
863                                         m = *((methodinfo **) (pv + MethodPointer));
864
865 #if defined(ENABLE_INTRP)
866                                         }
867 #endif
868                                 }
869                         }
870
871                         /* get previous stackframeinfo in the chain */
872
873                         sfi = sfi->prev;
874
875                 } else {
876 #if PRINTMETHODS
877                         utf_display_classname(m->class->name);
878                         printf(".");
879                         utf_display(m->name);
880                         utf_display(m->descriptor);
881                         printf(": JIT\n");
882 #endif
883
884                         /* JIT method found, add it to the stacktrace (we subtract 1 from */
885                         /* the return address since it points the the instruction after */
886                         /* call) */
887
888                         stacktrace_fillInStackTrace_method(&buffer, m, pv,
889                                                                                            (u1 *) ((ptrint) ra) - 1);
890
891                         /* get the current stack frame size */
892
893                         framesize = *((u4 *) (pv + FrameSize));
894
895                         /* get return address of current stack frame */
896
897                         ra = md_stacktrace_get_returnaddress(sp, framesize);
898
899                         /* get data segment and methodinfo pointer from parent method */
900
901                         pv = (u1 *) (ptrint) codegen_findmethod(ra);
902                         m = *((methodinfo **) (pv + MethodPointer));
903
904                         /* walk the stack */
905
906 #if defined(ENABLE_INTRP)
907                         if (opt_intrp)
908                                 sp = *(u1 **)(sp - framesize);
909                         else
910 #endif
911                                 {
912 #if defined(__I386__) || defined (__X86_64__)
913                                         sp += framesize + SIZEOF_VOID_P;
914 #else
915                                         sp += framesize;
916 #endif
917                                 }
918                 }
919         }
920                         
921         if (coll)
922                 result = coll(target, &buffer);
923
924         if (buffer.needsFree)
925                 free(buffer.start);
926
927         return result;
928 }
929
930
931 /* stackTraceCollector *********************************************************
932
933    XXX
934
935 *******************************************************************************/
936
937 static bool stackTraceCollector(void **target, stackTraceBuffer *buffer)
938 {
939         stackTraceBuffer *dest;
940
941         dest = *target = heap_allocate(sizeof(stackTraceBuffer) + buffer->full * sizeof(stacktraceelement), true, 0);
942
943         if (!dest)
944                 return false;
945
946         memcpy(*target, buffer, sizeof(stackTraceBuffer));
947         memcpy(dest + 1, buffer->start, buffer->full * sizeof(stacktraceelement));
948
949         dest->needsFree = 0;
950         dest->size = dest->full;
951         dest->start = (stacktraceelement *) (dest + 1);
952
953         return true;
954 }
955
956
957 bool cacao_stacktrace_NormalTrace(void **target)
958 {
959         return cacao_stacktrace_fillInStackTrace(target, &stackTraceCollector);
960 }
961
962
963
964 static bool classContextCollector(void **target, stackTraceBuffer *buffer)
965 {
966         java_objectarray  *oa;
967         stacktraceelement *current;
968         stacktraceelement *start;
969         size_t size;
970         size_t targetSize;
971         s4 i;
972
973         size = buffer->full;
974         targetSize = 0;
975
976         for (i = 0; i < size; i++)
977                 if (buffer->start[i].method != 0)
978                         targetSize++;
979
980         start = buffer->start;
981         start++;
982         targetSize--;
983
984         if (targetSize > 0) {
985                 if (start->method &&
986                         (start->method->class == class_java_lang_SecurityManager)) {
987                         targetSize--;
988                         start++;
989                 }
990         }
991
992         oa = builtin_anewarray(targetSize, class_java_lang_Class);
993
994         if (!oa)
995                 return false;
996
997         for(i = 0, current = start; i < targetSize; i++, current++) {
998                 if (!current->method) {
999                         i--;
1000                         continue;
1001                 }
1002
1003                 use_class_as_object(current->method->class);
1004
1005                 oa->data[i] = (java_objectheader *) current->method->class;
1006         }
1007
1008         *target = oa;
1009
1010         return true;
1011 }
1012
1013
1014
1015 java_objectarray *cacao_createClassContextArray(void)
1016 {
1017         java_objectarray *array = NULL;
1018
1019         if (!cacao_stacktrace_fillInStackTrace((void **) &array,
1020                                                                                    &classContextCollector))
1021                 return NULL;
1022
1023         return array;
1024 }
1025
1026
1027 /* stacktrace_classLoaderCollector *********************************************
1028
1029    XXX
1030
1031 *******************************************************************************/
1032
1033 static bool stacktrace_classLoaderCollector(void **target,
1034                                                                                         stackTraceBuffer *buffer)
1035 {
1036         stacktraceelement *current;
1037         stacktraceelement *start;
1038         methodinfo        *m;
1039         ptrint             size;
1040         s4                 i;
1041
1042         size = buffer->full;
1043         start = &(buffer->start[0]);
1044
1045         for(i = 0, current = start; i < size; i++, current++) {
1046                 m = current->method;
1047
1048                 if (!m)
1049                         continue;
1050
1051                 if (m->class == class_java_security_PrivilegedAction) {
1052                         *target = NULL;
1053                         return true;
1054                 }
1055
1056                 if (m->class->classloader) {
1057                         *target = (java_lang_ClassLoader *) m->class->classloader;
1058                         return true;
1059                 }
1060         }
1061
1062         *target = NULL;
1063
1064         return true;
1065 }
1066
1067
1068 /* cacao_currentClassLoader ****************************************************
1069
1070    XXX
1071
1072 *******************************************************************************/
1073
1074 java_objectheader *cacao_currentClassLoader(void)
1075 {
1076         java_objectheader *header = NULL;
1077
1078         if (!cacao_stacktrace_fillInStackTrace((void**)&header,
1079                                                                                    &stacktrace_classLoaderCollector))
1080                 return NULL;
1081
1082         return header;
1083 }
1084
1085
1086 static bool callingMethodCollector(void **target, stackTraceBuffer *buffer)
1087 {
1088         *target = buffer->start[1].method;
1089
1090         return true;
1091 }
1092
1093
1094 methodinfo *cacao_callingMethod(void)
1095 {
1096         methodinfo *method;
1097
1098         if (!cacao_stacktrace_fillInStackTrace((void **) &method,
1099                                                                                    &callingMethodCollector))
1100                 return NULL;
1101
1102         return method;
1103 }
1104
1105
1106 static bool getStackCollector(void **target, stackTraceBuffer *buffer)
1107 {
1108         java_objectarray  *oa;
1109         java_objectarray  *classes;
1110         java_objectarray  *methodnames;
1111         java_lang_String  *str;
1112         classinfo         *c;
1113         stacktraceelement *current;
1114         s4                 i, size;
1115
1116 /*      *result = (java_objectarray **) target; */
1117
1118         size = buffer->full;
1119
1120         oa = builtin_anewarray(2, arrayclass_java_lang_Object);
1121
1122         if (!oa)
1123                 return false;
1124
1125         classes = builtin_anewarray(size, class_java_lang_Class);
1126
1127         if (!classes)
1128                 return false;
1129
1130         methodnames = builtin_anewarray(size, class_java_lang_String);
1131
1132         if (!methodnames)
1133                 return false;
1134
1135         oa->data[0] = (java_objectheader *) classes;
1136         oa->data[1] = (java_objectheader *) methodnames;
1137
1138         for (i = 0, current = &(buffer->start[0]); i < size; i++, current++) {
1139                 c = current->method->class;
1140
1141                 use_class_as_object(c);
1142
1143                 classes->data[i] = (java_objectheader *) c;
1144                 str = javastring_new(current->method->name);
1145
1146                 if (!str)
1147                         return false;
1148
1149                 methodnames->data[i] = (java_objectheader *) str;
1150         }
1151
1152         *target = oa;
1153
1154         return true;
1155 }
1156
1157
1158 java_objectarray *cacao_getStackForVMAccessController(void)
1159 {
1160         java_objectarray *result = NULL;
1161
1162         if (!cacao_stacktrace_fillInStackTrace((void **) &result,
1163                                                                                    &getStackCollector))
1164                 return NULL;
1165
1166         return result;
1167 }
1168
1169
1170 /* stacktrace_dump_trace *******************************************************
1171
1172    This method is call from signal_handler_sigusr1 to dump the
1173    stacktrace of the current thread to stdout.
1174
1175 *******************************************************************************/
1176
1177 void stacktrace_dump_trace(void)
1178 {
1179         stackTraceBuffer      *buffer;
1180
1181 #if 0
1182         /* get thread stackframeinfo */
1183
1184         info = &THREADINFO->_stackframeinfo;
1185
1186         /* fill stackframeinfo structure */
1187
1188         tmp.oldThreadspecificHeadValue = *info;
1189         tmp.addressOfThreadspecificHead = info;
1190         tmp.method = NULL;
1191         tmp.sp = NULL;
1192         tmp.ra = _mc->gregs[REG_RIP];
1193
1194         *info = &tmp;
1195 #endif
1196
1197         /* generate stacktrace */
1198
1199         cacao_stacktrace_NormalTrace((void **) &buffer);
1200
1201         /* print stacktrace */
1202
1203         if (buffer)
1204                 stacktrace_print_trace(buffer);
1205 }
1206
1207
1208 /* stacktrace_print_trace ******************************************************
1209
1210    Print the stacktrace of a given stackTraceBuffer with CACAO intern
1211    methods (no Java help). This method is used by
1212    stacktrace_dump_trace and builtin_trace_exception.
1213
1214 *******************************************************************************/
1215
1216 void stacktrace_print_trace(stackTraceBuffer *stb)
1217 {
1218         stacktraceelement *ste;
1219         methodinfo        *m;
1220         s4                 i;
1221
1222         ste = stb->start;
1223
1224         for (i = 0; i < stb->size; i++, ste++) {
1225                 m = ste->method;
1226
1227                 printf("\tat ");
1228                 utf_display_classname(m->class->name);
1229                 printf(".");
1230                 utf_display(m->name);
1231                 utf_display(m->descriptor);
1232
1233                 if (m->flags & ACC_NATIVE) {
1234                         printf("(Native Method)\n");
1235
1236                 } else {
1237                         printf("(");
1238                         utf_display(m->class->sourcefile);
1239                         printf(":%d)\n", (u4) ste->linenumber);
1240                 }
1241         }
1242
1243         /* just to be sure */
1244
1245         fflush(stdout);
1246 }
1247
1248
1249 /*
1250  * These are local overrides for various environment variables in Emacs.
1251  * Please do not remove this and leave it at the end of the file, where
1252  * Emacs will automagically detect them.
1253  * ---------------------------------------------------------------------
1254  * Local variables:
1255  * mode: c
1256  * indent-tabs-mode: t
1257  * c-basic-offset: 4
1258  * tab-width: 4
1259  * End:
1260  */