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