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