dc59d296e4a1f5aa7d65e4ef0fc8c10a330bb871
[cacao.git] / src / vm / jit / stacktrace.c
1 /* src/vm/jit/stacktrace.c - machine independent stacktrace system
2
3    Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    $Id: stacktrace.c 8139 2007-06-24 10:12:27Z twisti $
26
27 */
28
29
30 #include "config.h"
31
32 #include <assert.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "vm/types.h"
37
38 #include "mm/gc-common.h"
39 #include "mm/memory.h"
40
41 #include "vm/jit/stacktrace.h"
42
43 #include "vm/global.h"                   /* required here for native includes */
44 #include "native/jni.h"
45 #include "native/include/java_lang_Throwable.h"
46
47 #if defined(WITH_CLASSPATH_GNU)
48 # include "native/include/java_lang_VMThrowable.h"
49 #endif
50
51 #if defined(ENABLE_THREADS)
52 # include "threads/native/threads.h"
53 #else
54 # include "threads/none/threads.h"
55 #endif
56
57 #include "toolbox/logging.h"
58
59 #include "vm/builtin.h"
60 #include "vm/cycles-stats.h"
61 #include "vm/exceptions.h"
62 #include "vm/stringlocal.h"
63 #include "vm/vm.h"
64
65 #include "vm/jit/asmpart.h"
66 #include "vm/jit/codegen-common.h"
67 #include "vm/jit/methodheader.h"
68
69 #include "vmcore/class.h"
70 #include "vmcore/loader.h"
71 #include "vmcore/options.h"
72
73
74 /* global variables ***********************************************************/
75 #if !defined(ENABLE_THREADS)
76 stackframeinfo *_no_threads_stackframeinfo = NULL;
77 #endif
78
79 CYCLES_STATS_DECLARE(stacktrace_overhead        ,100,1)
80 CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace,40,5000)
81 CYCLES_STATS_DECLARE(stacktrace_getClassContext ,40,5000)
82 CYCLES_STATS_DECLARE(stacktrace_getCurrentClass ,40,5000)
83 CYCLES_STATS_DECLARE(stacktrace_getStack        ,40,10000)
84
85
86 /* stacktrace_create_stackframeinfo ********************************************
87
88    Creates an stackframe info structure for inline code in the
89    interpreter.
90
91 *******************************************************************************/
92
93 #if defined(ENABLE_INTRP)
94 void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv, u1 *sp,
95                                                                           u1 *ra)
96 {
97         stackframeinfo **psfi;
98         methodinfo      *m;
99         codeinfo        *code;
100
101         /* get current stackframe info pointer */
102
103         psfi = &STACKFRAMEINFO;
104
105         /* if we don't have pv handy */
106
107         if (pv == NULL) {
108 #if defined(ENABLE_INTRP)
109                 if (opt_intrp)
110                         pv = codegen_get_pv_from_pc(ra);
111                 else
112 #endif
113                         {
114 #if defined(ENABLE_JIT)
115                                 pv = md_codegen_get_pv_from_pc(ra);
116 #endif
117                         }
118         }
119
120         /* get codeinfo pointer from data segment */
121
122         code = *((codeinfo **) (pv + CodeinfoPointer));
123
124         /* For asm_vm_call_method the codeinfo pointer is NULL. */
125
126         m = (code == NULL) ? NULL : code->m;
127
128         /* fill new stackframe info structure */
129
130         sfi->prev   = *psfi;
131         sfi->method = m;
132         sfi->pv     = pv;
133         sfi->sp     = sp;
134         sfi->ra     = ra;
135
136         /* xpc is the same as ra, but is required in stacktrace_create */
137
138         sfi->xpc    = ra;
139
140         /* store new stackframe info pointer */
141
142         *psfi = sfi;
143 }
144 #endif /* defined(ENABLE_INTRP) */
145
146
147 /* stacktrace_create_extern_stackframeinfo *************************************
148
149    Creates an stackframe info structure for an extern exception
150    (hardware or assembler).
151
152 *******************************************************************************/
153
154 void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
155                                                                                          u1 *sp, u1 *ra, u1 *xpc)
156 {
157         stackframeinfo **psfi;
158 #if !defined(__I386__) && !defined(__X86_64__) && !defined(__S390__) && !defined(__M68K__)
159         bool             isleafmethod;
160 #endif
161 #if defined(ENABLE_JIT)
162         s4               framesize;
163 #endif
164
165         /* get current stackframe info pointer */
166
167         psfi = &STACKFRAMEINFO;
168
169         /* sometimes we don't have pv handy (e.g. in asmpart.S:
170        L_asm_call_jit_compiler_exception or in the interpreter). */
171
172         if (pv == NULL) {
173 #if defined(ENABLE_INTRP)
174                 if (opt_intrp)
175                         pv = codegen_get_pv_from_pc(ra);
176                 else
177 #endif
178                         {
179 #if defined(ENABLE_JIT)
180 # if defined(__SPARC_64__)
181                                 pv = md_get_pv_from_stackframe(sp);
182 # else
183                                 pv = md_codegen_get_pv_from_pc(ra);
184 # endif
185 #endif
186                         }
187         }
188
189 #if defined(ENABLE_JIT)
190 # if defined(ENABLE_INTRP)
191         /* When using the interpreter, we pass RA to the function. */
192
193         if (!opt_intrp) {
194 # endif
195 # if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__M68K__)
196                 /* On i386 and x86_64 we always have to get the return address
197                    from the stack. */
198                 /* m68k has return address on stack always */
199                 /* On S390 we use REG_RA as REG_ITMP3, so we have always to get
200                    the RA from stack. */
201
202                 framesize = *((u4 *) (pv + FrameSize));
203
204                 ra = md_stacktrace_get_returnaddress(sp, framesize);
205 # else
206                 /* If the method is a non-leaf function, we need to get the return
207                    address from the stack. For leaf functions the return address
208                    is set correctly. This makes the assembler and the signal
209                    handler code simpler. */
210
211                 isleafmethod = *((s4 *) (pv + IsLeaf));
212
213                 if (!isleafmethod) {
214                         framesize = *((u4 *) (pv + FrameSize));
215
216                         ra = md_stacktrace_get_returnaddress(sp, framesize);
217                 }
218 # endif
219 # if defined(ENABLE_INTRP)
220         }
221 # endif
222 #endif /* defined(ENABLE_JIT) */
223
224         /* fill new stackframe info structure */
225
226         sfi->prev   = *psfi;
227         sfi->method = NULL;
228         sfi->pv     = pv;
229         sfi->sp     = sp;
230         sfi->ra     = ra;
231         sfi->xpc    = xpc;
232
233         /* store new stackframe info pointer */
234
235         *psfi = sfi;
236 }
237
238
239 /* stacktrace_create_native_stackframeinfo *************************************
240
241    Creates a stackframe info structure for a native stub.
242
243 *******************************************************************************/
244
245 void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv,
246                                                                                          u1 *sp, u1 *ra)
247 {
248         stackframeinfo **psfi;
249         methodinfo      *m;
250         codeinfo        *code;
251
252         /* get codeinfo pointer from data segment */
253
254         code = *((codeinfo **) (pv + CodeinfoPointer));
255
256         /* For asm_vm_call_method the codeinfo pointer is NULL. */
257
258         m = (code == NULL) ? NULL : code->m;
259
260         /* get current stackframe info pointer */
261
262         psfi = &STACKFRAMEINFO;
263
264         /* fill new stackframe info structure */
265
266         sfi->prev   = *psfi;
267         sfi->method = m;
268         sfi->pv     = NULL;
269         sfi->sp     = sp;
270         sfi->ra     = ra;
271         sfi->xpc    = NULL;
272
273         /* store new stackframe info pointer */
274
275         *psfi = sfi;
276 }
277
278
279 /* stacktrace_remove_stackframeinfo ********************************************
280
281    Remove the topmost stackframeinfo in the current thread.
282
283 *******************************************************************************/
284
285 void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
286 {
287         stackframeinfo **psfi;
288
289         /* get current stackframe info pointer */
290
291         psfi = &STACKFRAMEINFO;
292
293         /* restore the old pointer */
294
295         *psfi = sfi->prev;
296 }
297
298
299 /* stacktrace_add_entry ********************************************************
300
301    Adds a new entry to the stacktrace buffer.
302
303 *******************************************************************************/
304
305 static void stacktrace_add_entry(stacktracebuffer *stb, methodinfo *m, u2 line)
306 {
307         stacktrace_entry *ste;
308
309         /* check if we already reached the buffer capacity */
310
311         if (stb->used >= stb->capacity) {
312                 /* reallocate new memory */
313
314                 stb->entries = DMREALLOC(stb->entries, stacktrace_entry, stb->capacity,
315                                                                  stb->capacity + STACKTRACE_CAPACITY_INCREMENT);
316
317                 /* set new buffer capacity */
318
319                 stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
320         }
321
322         /* insert the current entry */
323
324         ste = &(stb->entries[stb->used]);
325
326         ste->method     = m;
327         ste->linenumber = line;
328
329         /* increase entries used count */
330
331         stb->used += 1;
332 }
333
334
335 /* stacktrace_add_method *******************************************************
336
337    Add stacktrace entries[1] for the given method to the stacktrace buffer.
338
339    IN:
340        stb.........stacktracebuffer to fill
341            m...........method for which entries should be created
342            pv..........pv of method
343            pc..........position of program counter within the method's code
344
345    OUT:
346        true, if stacktrace entries were successfully created, false otherwise.
347
348    [1] In case of inlined methods there may be more than one stacktrace
349        entry for a codegen-level method. (see doc/inlining_stacktrace.txt)
350
351 *******************************************************************************/
352
353 static bool stacktrace_add_method(stacktracebuffer *stb, methodinfo *m, u1 *pv,
354                                                                   u1 *pc)
355 {
356         codeinfo *code;                     /* compiled realization of method     */
357         s4        linenumber;
358
359         /* find the realization of the method the pc is in */
360
361         code = *((codeinfo **) (pv + CodeinfoPointer));
362
363         /* search the line number table */
364
365         linenumber = dseg_get_linenumber_from_pc(&m, pv, pc);
366
367         /* now add a new entry to the staktrace */
368
369         stacktrace_add_entry(stb, m, linenumber);
370
371         return true;
372 }
373
374
375 /* stacktrace_create ***********************************************************
376
377    Generates a stacktrace from the thread passed into a
378    stacktracebuffer.  The stacktracebuffer is allocated on the
379    dump memory.
380    
381    NOTE: The first element in the stackframe chain must always be a
382          native stackframeinfo (e.g. VMThrowable.fillInStackTrace() is
383          a native function).
384
385    RETURN VALUE:
386       pointer to the stacktracebuffer, or
387       NULL if there is no stacktrace available for the
388       given thread.
389
390 *******************************************************************************/
391
392 stacktracebuffer *stacktrace_create(stackframeinfo *sfi)
393 {
394         stacktracebuffer *stb;
395         methodinfo       *m;
396         codeinfo         *code;
397         u1               *pv;
398         u1               *sp;
399         u4                framesize;
400         u1               *ra;
401         u1               *xpc;
402
403         /* prevent compiler warnings */
404
405         pv = NULL;
406         sp = NULL;
407         ra = NULL;
408
409         /* create a stacktracebuffer in dump memory */
410
411         stb = DNEW(stacktracebuffer);
412
413         stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
414         stb->used     = 0;
415         stb->entries  = DMNEW(stacktrace_entry, STACKTRACE_CAPACITY_DEFAULT);
416
417 #define PRINTMETHODS 0
418
419 #if PRINTMETHODS
420         printf("\n\nfillInStackTrace start:\n");
421         fflush(stdout);
422 #endif
423
424         /* Loop while we have a method pointer (asm_calljavafunction has
425            NULL) or there is a stackframeinfo in the chain. */
426
427         m = NULL;
428
429         while ((m != NULL) || (sfi != NULL)) {
430                 /* m == NULL should only happen for the first time and inline
431                    stackframe infos, like from the exception stubs or the
432                    patcher wrapper. */
433
434                 if (m == NULL) {
435                         /* for native stub stackframe infos, pv is always NULL */
436
437                         if (sfi->pv == NULL) {
438                                 /* get methodinfo, sp and ra from the current stackframe info */
439
440                                 m  = sfi->method;
441                                 sp = sfi->sp;           /* sp of parent Java function         */
442                                 ra = sfi->ra;
443
444                                 if (m)
445                                         stacktrace_add_entry(stb, m, 0);
446
447 #if PRINTMETHODS
448                                 printf("ra=%p sp=%p, ", ra, sp);
449                                 method_print(m);
450                                 printf(": native stub\n");
451                                 fflush(stdout);
452 #endif
453                                 /* This is an native stub stackframe info, so we can
454                                    get the parent pv from the return address
455                                    (ICMD_INVOKE*). */
456
457 #if defined(ENABLE_INTRP)
458                                 if (opt_intrp)
459                                         pv = codegen_get_pv_from_pc(ra);
460                                 else
461 #endif
462                                         {
463 #if defined(ENABLE_JIT)
464                                                 pv = md_codegen_get_pv_from_pc(ra);
465 #endif
466                                         }
467
468                                 /* get methodinfo pointer from parent data segment */
469
470                                 code = *((codeinfo **) (pv + CodeinfoPointer));
471
472                                 /* For asm_vm_call_method the codeinfo pointer is
473                                    NULL. */
474
475                                 m = (code == NULL) ? NULL : code->m;
476
477                         } else {
478                                 /* Inline stackframe infos are special: they have a
479                                    xpc of the actual exception position and the return
480                                    address saved since an inline stackframe info can
481                                    also be in a leaf method (no return address saved
482                                    on stack!!!).  ATTENTION: This one is also for
483                                    hardware exceptions!!! */
484
485                                 /* get methodinfo, sp and ra from the current stackframe info */
486
487                                 m   = sfi->method;      /* m == NULL                          */
488                                 pv  = sfi->pv;          /* pv of parent Java function         */
489                                 sp  = sfi->sp;          /* sp of parent Java function         */
490                                 ra  = sfi->ra;          /* ra of parent Java function         */
491                                 xpc = sfi->xpc;         /* actual exception position          */
492
493 #if PRINTMETHODS
494                                 printf("ra=%p sp=%p, ", ra, sp);
495                                 printf("NULL: inline stub\n");
496                                 fflush(stdout);
497 #endif
498
499                                 /* get methodinfo from current Java method */
500
501                                 code = *((codeinfo **) (pv + CodeinfoPointer));
502
503                                 /* For asm_vm_call_method the codeinfo pointer is
504                                    NULL. */
505
506                                 m = (code == NULL) ? NULL : code->m;
507
508                                 /* if m == NULL, this is a asm_calljavafunction call */
509
510                                 if (m != NULL) {
511 #if PRINTMETHODS
512                                         printf("ra=%p sp=%p, ", ra, sp);
513                                         method_print(m);
514                                         printf(": inline stub parent");
515                                         fflush(stdout);
516 #endif
517
518 #if defined(ENABLE_INTRP)
519                                         if (!opt_intrp) {
520 #endif
521
522                                         /* add the method to the stacktrace */
523
524                                         stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) xpc));
525
526                                         /* get the current stack frame size */
527
528                                         framesize = *((u4 *) (pv + FrameSize));
529
530 #if PRINTMETHODS
531                                         printf(", framesize=%d\n", framesize);
532                                         fflush(stdout);
533 #endif
534
535                                         /* Set stack pointer to stackframe of parent Java
536                                            function of the current Java function. */
537
538 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
539                                         sp += framesize + SIZEOF_VOID_P;
540 #elif defined(__SPARC_64__)
541                                         sp = md_get_framepointer(sp);
542 #else
543                                         sp += framesize;
544 #endif
545
546                                         /* get data segment and methodinfo pointer from
547                                            parent method */
548
549 #if defined(ENABLE_JIT)
550                                         pv = md_codegen_get_pv_from_pc(ra);
551 #endif
552
553                                         code = *((codeinfo **) (pv + CodeinfoPointer));
554
555                                         /* For asm_vm_call_method the codeinfo pointer is
556                                            NULL. */
557
558                                         m = (code == NULL) ? NULL : code->m;
559
560 #if defined(ENABLE_INTRP)
561                                         }
562 #endif
563                                 }
564 #if PRINTMETHODS
565                                 else {
566                                         printf("ra=%p sp=%p, ", ra, sp);
567                                         printf("asm_calljavafunction\n");
568                                         fflush(stdout);
569                                 }
570 #endif
571                         }
572
573                         /* get previous stackframeinfo in the chain */
574
575                         sfi = sfi->prev;
576
577                 } else {
578 #if PRINTMETHODS
579                         printf("ra=%p sp=%p, ", ra, sp);
580                         method_print(m);
581                         printf(": JIT");
582                         fflush(stdout);
583 #endif
584
585                         /* JIT method found, add it to the stacktrace (we subtract
586                            1 from the return address since it points the the
587                            instruction after call). */
588
589                         stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1);
590
591                         /* get the current stack frame size */
592
593                         framesize = *((u4 *) (pv + FrameSize));
594
595 #if PRINTMETHODS
596                         printf(", framesize=%d\n", framesize);
597                         fflush(stdout);
598 #endif
599
600                         /* get return address of current stack frame */
601
602 #if defined(ENABLE_JIT)
603 # if defined(ENABLE_INTRP)
604                         if (opt_intrp)
605                                 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
606                         else
607 # endif
608                                 ra = md_stacktrace_get_returnaddress(sp, framesize);
609 #else
610                         ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
611 #endif
612
613                         /* get data segment and methodinfo pointer from parent method */
614
615 #if defined(ENABLE_INTRP)
616                         if (opt_intrp)
617                                 pv = codegen_get_pv_from_pc(ra);
618                         else
619 #endif
620                                 {
621 #if defined(ENABLE_JIT)
622 # if defined(__SPARC_64__)
623                                         sp = md_get_framepointer(sp);
624                                         pv = md_get_pv_from_stackframe(sp);
625 # else
626                                         pv = md_codegen_get_pv_from_pc(ra);
627 # endif
628 #endif
629                                 }
630
631                         code = *((codeinfo **) (pv + CodeinfoPointer));
632
633                         /* For asm_vm_call_method the codeinfo pointer is NULL. */
634
635                         m = (code == NULL) ? NULL : code->m;
636
637                         /* walk the stack */
638
639 #if defined(ENABLE_INTRP)
640                         if (opt_intrp)
641                                 sp = *(u1 **) (sp - framesize);
642                         else
643 #endif
644                                 {
645 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
646                                         sp += framesize + SIZEOF_VOID_P;
647 #elif defined(__SPARC_64__)
648                                         /* already has the new sp */
649 #else
650                                         sp += framesize;
651 #endif
652                                 }
653                 }
654         }
655
656         /* return the stacktracebuffer */
657
658         if (stb->used == 0)
659                 return NULL;
660         else
661                 return stb;
662 }
663
664
665 /* stacktrace_fillInStackTrace *************************************************
666
667    Generate a stacktrace from the current thread for
668    java.lang.VMThrowable.fillInStackTrace.
669
670 *******************************************************************************/
671
672 stacktracecontainer *stacktrace_fillInStackTrace(void)
673 {
674         stacktracebuffer    *stb;
675         stacktracecontainer *gcstc;
676         s4                   gcstc_size;
677         s4                   dumpsize;
678         CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
679
680         /* mark start of dump memory area */
681
682         dumpsize = dump_size();
683
684         /* create a stacktrace from the current thread */
685
686         stb = stacktrace_create(STACKFRAMEINFO);
687
688         if (stb == NULL)
689                 goto return_NULL;
690
691         /* allocate memory from the GC heap and copy the stacktrace buffer */
692         /* ATTENTION: use stacktracecontainer for this and make it look like
693        an array */
694
695         gcstc_size = sizeof(stacktracebuffer) +
696                      sizeof(stacktrace_entry) * stb->used;
697         gcstc = (stacktracecontainer *) builtin_newarray_byte(gcstc_size);
698
699         if (gcstc == NULL)
700                 goto return_NULL;
701
702         gcstc->stb.capacity = stb->capacity;
703         gcstc->stb.used     = stb->used;
704         gcstc->stb.entries  = gcstc->data;
705
706         MCOPY(gcstc->data, stb->entries, stacktrace_entry, stb->used);
707
708         /* release dump memory */
709
710         dump_release(dumpsize);
711
712         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
713                                                                    stacktrace_overhead)
714         return gcstc;
715
716 return_NULL:
717         dump_release(dumpsize);
718
719         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
720                                                                    stacktrace_overhead)
721
722         return NULL;
723 }
724
725
726 /* stacktrace_getClassContext **************************************************
727
728    Creates a Class context array.
729
730    RETURN VALUE:
731       the array of java.lang.Class objects, or
732           NULL if an exception has been thrown
733
734 *******************************************************************************/
735
736 java_objectarray *stacktrace_getClassContext(void)
737 {
738         stacktracebuffer  *stb;
739         stacktrace_entry  *ste;
740         java_objectarray  *oa;
741         s4                 oalength;
742         s4                 i;
743         s4                 dumpsize;
744         CYCLES_STATS_DECLARE_AND_START
745
746         /* mark start of dump memory area */
747
748         dumpsize = dump_size();
749
750         /* create a stacktrace for the current thread */
751
752         stb = stacktrace_create(STACKFRAMEINFO);
753
754         if (stb == NULL)
755                 goto return_NULL;
756
757         /* calculate the size of the Class array */
758
759         for (i = 0, oalength = 0; i < stb->used; i++)
760                 if (stb->entries[i].method != NULL)
761                         oalength++;
762
763         /* The first entry corresponds to the method whose implementation */
764         /* calls stacktrace_getClassContext. We remove that entry.        */
765
766         ste = &(stb->entries[0]);
767         ste++;
768         oalength--;
769
770         /* allocate the Class array */
771
772         oa = builtin_anewarray(oalength, class_java_lang_Class);
773         if (!oa)
774                 goto return_NULL;
775
776         /* fill the Class array from the stacktracebuffer */
777
778         for(i = 0; i < oalength; i++, ste++) {
779                 if (ste->method == NULL) {
780                         i--;
781                         continue;
782                 }
783
784                 oa->data[i] = (java_objectheader *) ste->method->class;
785         }
786
787         /* release dump memory */
788
789         dump_release(dumpsize);
790
791         CYCLES_STATS_END(stacktrace_getClassContext)
792
793         return oa;
794
795 return_NULL:
796         dump_release(dumpsize);
797
798         CYCLES_STATS_END(stacktrace_getClassContext)
799
800         return NULL;
801 }
802
803
804 /* stacktrace_getCurrentClass **************************************************
805
806    Find the current class by walking the stack trace.
807
808    Quote from the JNI documentation:
809          
810    In the Java 2 Platform, FindClass locates the class loader
811    associated with the current native method.  If the native code
812    belongs to a system class, no class loader will be
813    involved. Otherwise, the proper class loader will be invoked to
814    load and link the named class. When FindClass is called through the
815    Invocation Interface, there is no current native method or its
816    associated class loader. In that case, the result of
817    ClassLoader.getBaseClassLoader is used."
818
819 *******************************************************************************/
820
821 #if defined(ENABLE_JAVASE)
822 classinfo *stacktrace_getCurrentClass(void)
823 {
824         stacktracebuffer  *stb;
825         stacktrace_entry  *ste;
826         methodinfo        *m;
827         s4                 i;
828         s4                 dumpsize;
829         CYCLES_STATS_DECLARE_AND_START
830
831         /* mark start of dump memory area */
832
833         dumpsize = dump_size();
834
835         /* create a stacktrace for the current thread */
836
837         stb = stacktrace_create(STACKFRAMEINFO);
838
839         if (stb == NULL)
840                 goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
841
842         /* iterate over all stacktrace entries and find the first suitable
843            class */
844
845         for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
846                 m = ste->method;
847
848                 if (m == NULL)
849                         continue;
850
851                 if (m->class == class_java_security_PrivilegedAction)
852                         goto return_NULL;
853
854                 if (m->class != NULL) {
855                         dump_release(dumpsize);
856
857                         CYCLES_STATS_END(stacktrace_getCurrentClass)
858
859                         return m->class;
860                 }
861         }
862
863         /* no Java method found on the stack */
864
865 return_NULL:
866         dump_release(dumpsize);
867
868         CYCLES_STATS_END(stacktrace_getCurrentClass)
869
870         return NULL;
871 }
872 #endif /* ENABLE_JAVASE */
873
874
875 /* stacktrace_getStack *********************************************************
876
877    Create a 2-dimensional array for java.security.VMAccessControler.
878
879    RETURN VALUE:
880       the arrary, or
881           NULL if an exception has been thrown
882
883 *******************************************************************************/
884
885 #if defined(ENABLE_JAVASE)
886 java_objectarray *stacktrace_getStack(void)
887 {
888         stacktracebuffer  *stb;
889         stacktrace_entry  *ste;
890         java_objectarray  *oa;
891         java_objectarray  *classes;
892         java_objectarray  *methodnames;
893         classinfo         *c;
894         java_objectheader *string;
895         s4                 i;
896         s4                 dumpsize;
897         CYCLES_STATS_DECLARE_AND_START
898
899         /* mark start of dump memory area */
900
901         dumpsize = dump_size();
902
903         /* create a stacktrace for the current thread */
904
905         stb = stacktrace_create(STACKFRAMEINFO);
906
907         if (stb == NULL)
908                 goto return_NULL;
909
910         /* get the first stacktrace entry */
911
912         ste = &(stb->entries[0]);
913
914         /* allocate all required arrays */
915
916         oa = builtin_anewarray(2, arrayclass_java_lang_Object);
917
918         if (oa == NULL)
919                 goto return_NULL;
920
921         classes = builtin_anewarray(stb->used, class_java_lang_Class);
922
923         if (classes == NULL)
924                 goto return_NULL;
925
926         methodnames = builtin_anewarray(stb->used, class_java_lang_String);
927
928         if (methodnames == NULL)
929                 goto return_NULL;
930
931         /* set up the 2-dimensional array */
932
933         oa->data[0] = (java_objectheader *) classes;
934         oa->data[1] = (java_objectheader *) methodnames;
935
936         /* iterate over all stacktrace entries */
937
938         for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
939                 c = ste->method->class;
940
941                 classes->data[i] = (java_objectheader *) c;
942
943                 string = javastring_new(ste->method->name);
944
945                 if (string == NULL)
946                         goto return_NULL;
947
948                 methodnames->data[i] = string;
949         }
950
951         /* return the 2-dimensional array */
952
953         dump_release(dumpsize);
954
955         CYCLES_STATS_END(stacktrace_getStack)
956
957         return oa;
958
959 return_NULL:
960         dump_release(dumpsize);
961
962         CYCLES_STATS_END(stacktrace_getStack)
963
964         return NULL;
965 }
966 #endif /* ENABLE_JAVASE */
967
968
969 /* stacktrace_print_trace_from_buffer ******************************************
970
971    Print the stacktrace of a given stacktracebuffer with CACAO intern
972    methods (no Java help). This method is used by
973    stacktrace_dump_trace and builtin_trace_exception.
974
975 *******************************************************************************/
976
977 void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
978 {
979         stacktrace_entry *ste;
980         methodinfo       *m;
981         s4                i;
982
983         ste = &(stb->entries[0]);
984
985         for (i = 0; i < stb->used; i++, ste++) {
986                 m = ste->method;
987
988                 printf("\tat ");
989                 utf_display_printable_ascii_classname(m->class->name);
990                 printf(".");
991                 utf_display_printable_ascii(m->name);
992                 utf_display_printable_ascii(m->descriptor);
993
994                 if (m->flags & ACC_NATIVE) {
995                         puts("(Native Method)");
996
997                 } else {
998                         printf("(");
999                         utf_display_printable_ascii(m->class->sourcefile);
1000                         printf(":%d)\n", (u4) ste->linenumber);
1001                 }
1002         }
1003
1004         /* just to be sure */
1005
1006         fflush(stdout);
1007 }
1008
1009
1010 /* stacktrace_print_trace ******************************************************
1011
1012    Print the stacktrace of a given exception. More or less a wrapper
1013    to stacktrace_print_trace_from_buffer.
1014
1015 *******************************************************************************/
1016
1017 void stacktrace_print_trace(java_objectheader *xptr)
1018 {
1019         java_lang_Throwable   *t;
1020 #if defined(WITH_CLASSPATH_GNU)
1021         java_lang_VMThrowable *vmt;
1022 #endif
1023         stacktracecontainer   *stc;
1024         stacktracebuffer      *stb;
1025
1026         t = (java_lang_Throwable *) xptr;
1027
1028         if (t == NULL)
1029                 return;
1030
1031         /* now print the stacktrace */
1032
1033 #if defined(WITH_CLASSPATH_GNU)
1034         vmt = t->vmState;
1035         stc = (stacktracecontainer *) vmt->vmData;
1036 #elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
1037         stc = (stacktracecontainer *) t->backtrace;
1038 #else
1039 # error unknown classpath configuration
1040 #endif
1041
1042         stb = &(stc->stb);
1043
1044         stacktrace_print_trace_from_buffer(stb);
1045 }
1046
1047
1048 #if defined(ENABLE_CYCLES_STATS)
1049 void stacktrace_print_cycles_stats(FILE *file)
1050 {
1051         CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
1052         CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
1053         CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
1054         CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
1055         CYCLES_STATS_PRINT(stacktrace_getStack        ,file);
1056 }
1057 #endif
1058
1059
1060 /*
1061  * These are local overrides for various environment variables in Emacs.
1062  * Please do not remove this and leave it at the end of the file, where
1063  * Emacs will automagically detect them.
1064  * ---------------------------------------------------------------------
1065  * Local variables:
1066  * mode: c
1067  * indent-tabs-mode: t
1068  * c-basic-offset: 4
1069  * tab-width: 4
1070  * End:
1071  * vim:noexpandtab:sw=4:ts=4:
1072  */