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