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