* Merged with 79e3a1932e59.
[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 #if !defined(NDEBUG)
446         if (opt_DebugStackTrace) {
447                 printf("\n\n---> stacktrace creation start (fillInStackTrace):\n");
448                 fflush(stdout);
449         }
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 && !(m->flags & ACC_METHOD_BUILTIN))
473                                         stb = stacktrace_add_entry(stb, m, 0);
474
475 #if !defined(NDEBUG)
476                                 if (opt_DebugStackTrace) {
477                                         printf("ra=%p sp=%p, ", ra, sp);
478                                         method_print(m);
479                                         printf(": native stub\n");
480                                         fflush(stdout);
481                                 }
482 #endif
483                                 /* This is an native stub stackframe info, so we can
484                                    get the parent pv from the return address
485                                    (ICMD_INVOKE*). */
486
487 #if defined(ENABLE_INTRP)
488                                 if (opt_intrp)
489                                         pv = codegen_get_pv_from_pc(ra);
490                                 else
491 #endif
492                                         {
493 #if defined(ENABLE_JIT)
494                                                 pv = md_codegen_get_pv_from_pc(ra);
495 #endif
496                                         }
497
498                                 /* get methodinfo pointer from parent data segment */
499
500                                 code = *((codeinfo **) (pv + CodeinfoPointer));
501
502                                 /* For asm_vm_call_method the codeinfo pointer is
503                                    NULL. */
504
505                                 m = (code == NULL) ? NULL : code->m;
506
507                         } else {
508                                 /* Inline stackframe infos are special: they have a
509                                    xpc of the actual exception position and the return
510                                    address saved since an inline stackframe info can
511                                    also be in a leaf method (no return address saved
512                                    on stack!!!).  ATTENTION: This one is also for
513                                    hardware exceptions!!! */
514
515                                 /* get methodinfo, sp and ra from the current stackframe info */
516
517                                 m   = sfi->method;      /* m == NULL                          */
518                                 pv  = sfi->pv;          /* pv of parent Java function         */
519                                 sp  = sfi->sp;          /* sp of parent Java function         */
520                                 ra  = sfi->ra;          /* ra of parent Java function         */
521                                 xpc = sfi->xpc;         /* actual exception position          */
522
523 #if !defined(NDEBUG)
524                                 if (opt_DebugStackTrace) {
525                                         printf("ra=%p sp=%p, ", ra, sp);
526                                         printf("NULL: extern stackframe\n");
527                                         fflush(stdout);
528                                 }
529 #endif
530
531                                 /* get methodinfo from current Java method */
532
533                                 code = *((codeinfo **) (pv + CodeinfoPointer));
534
535                                 /* For asm_vm_call_method the codeinfo pointer is
536                                    NULL. */
537
538                                 m = (code == NULL) ? NULL : code->m;
539
540                                 /* if m == NULL, this is a asm_calljavafunction call */
541
542                                 if (m != NULL) {
543 #if !defined(NDEBUG)
544                                         if (opt_DebugStackTrace) {
545                                                 printf("ra=%p sp=%p, ", ra, sp);
546                                                 method_print(m);
547                                                 printf(": extern stackframe parent");
548                                                 fflush(stdout);
549                                         }
550 #endif
551
552 #if defined(ENABLE_INTRP)
553                                         if (!opt_intrp) {
554 #endif
555
556                                         /* add the method to the stacktrace */
557
558                                         stb = stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) xpc));
559
560                                         /* get the current stack frame size */
561
562                                         framesize = *((u4 *) (pv + FrameSize));
563
564 #if !defined(NDEBUG)
565                                         if (opt_DebugStackTrace) {
566                                                 printf(", framesize=%d\n", framesize);
567                                                 fflush(stdout);
568                                         }
569 #endif
570
571                                         /* Set stack pointer to stackframe of parent Java
572                                            function of the current Java function. */
573
574 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
575                                         sp += framesize + SIZEOF_VOID_P;
576 #elif defined(__SPARC_64__)
577                                         sp = md_get_framepointer(sp);
578 #else
579                                         sp += framesize;
580 #endif
581
582                                         /* get data segment and methodinfo pointer from
583                                            parent method */
584
585 #if defined(ENABLE_JIT)
586                                         pv = md_codegen_get_pv_from_pc(ra);
587 #endif
588
589                                         code = *((codeinfo **) (pv + CodeinfoPointer));
590
591                                         /* For asm_vm_call_method the codeinfo pointer is
592                                            NULL. */
593
594                                         m = (code == NULL) ? NULL : code->m;
595
596 #if defined(ENABLE_INTRP)
597                                         }
598 #endif
599                                 }
600 #if !defined(NDEBUG)
601                                 else {
602                                         if (opt_DebugStackTrace) {
603                                                 printf("ra=%p sp=%p, ", ra, sp);
604                                                 printf("asm_calljavafunction\n");
605                                                 fflush(stdout);
606                                         }
607                                 }
608 #endif
609                         }
610
611                         /* get previous stackframeinfo in the chain */
612
613                         sfi = sfi->prev;
614
615                 } else {
616 #if !defined(NDEBUG)
617                         if (opt_DebugStackTrace) {
618                                 printf("ra=%p sp=%p, ", ra, sp);
619                                 method_print(m);
620                                 printf(": JIT");
621                                 fflush(stdout);
622                         }
623 #endif
624
625                         /* JIT method found, add it to the stacktrace (we subtract
626                            1 from the return address since it points the the
627                            instruction after call). */
628
629                         stb = stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1);
630
631                         /* get the current stack frame size */
632
633                         framesize = *((u4 *) (pv + FrameSize));
634
635 #if !defined(NDEBUG)
636                         if (opt_DebugStackTrace) {
637                                 printf(", framesize=%d\n", framesize);
638                                 fflush(stdout);
639                         }
640 #endif
641
642                         /* get return address of current stack frame */
643
644 #if defined(ENABLE_JIT)
645 # if defined(ENABLE_INTRP)
646                         if (opt_intrp)
647                                 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
648                         else
649 # endif
650                                 ra = md_stacktrace_get_returnaddress(sp, framesize);
651 #else
652                         ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
653 #endif
654
655                         /* get data segment and methodinfo pointer from parent method */
656
657 #if defined(ENABLE_INTRP)
658                         if (opt_intrp)
659                                 pv = codegen_get_pv_from_pc(ra);
660                         else
661 #endif
662                                 {
663 #if defined(ENABLE_JIT)
664 # if defined(__SPARC_64__)
665                                         sp = md_get_framepointer(sp);
666                                         pv = md_get_pv_from_stackframe(sp);
667 # else
668                                         pv = md_codegen_get_pv_from_pc(ra);
669 # endif
670 #endif
671                                 }
672
673                         code = *((codeinfo **) (pv + CodeinfoPointer));
674
675                         /* For asm_vm_call_method the codeinfo pointer is NULL. */
676
677                         m = (code == NULL) ? NULL : code->m;
678
679                         /* walk the stack */
680
681 #if defined(ENABLE_INTRP)
682                         if (opt_intrp)
683                                 sp = *(u1 **) (sp - framesize);
684                         else
685 #endif
686                                 {
687 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
688                                         sp += framesize + SIZEOF_VOID_P;
689 #elif defined(__SPARC_64__)
690                                         /* already has the new sp */
691 #else
692                                         sp += framesize;
693 #endif
694                                 }
695                 }
696         }
697
698 #if !defined(NDEBUG)
699         if (opt_DebugStackTrace) {
700                 printf("---> stacktrace creation finished.\n\n");
701                 fflush(stdout);
702         }
703 #endif
704
705         /* return the stacktracebuffer */
706
707         if (stb->used == 0)
708                 return NULL;
709         else
710                 return stb;
711 }
712
713
714 /* stacktrace_fillInStackTrace *************************************************
715
716    Generate a stacktrace from the current thread for
717    java.lang.VMThrowable.fillInStackTrace.
718
719 *******************************************************************************/
720
721 stacktracecontainer *stacktrace_fillInStackTrace(void)
722 {
723         stacktracebuffer    *stb;
724         stacktracecontainer *gcstc;
725         s4                   gcstc_size;
726         s4                   dumpsize;
727         CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
728
729         /* mark start of dump memory area */
730
731         dumpsize = dump_size();
732
733         /* create a stacktrace from the current thread */
734
735         stb = stacktrace_create(STACKFRAMEINFO);
736
737         if (stb == NULL)
738                 goto return_NULL;
739
740         /* allocate memory from the GC heap and copy the stacktrace buffer */
741         /* ATTENTION: use stacktracecontainer for this and make it look like
742        an array */
743
744         gcstc_size = sizeof(stacktracebuffer) +
745                      sizeof(stacktrace_entry) * stb->used -
746                                  sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_DEFAULT;
747         gcstc = (stacktracecontainer *) builtin_newarray_byte(gcstc_size);
748
749         if (gcstc == NULL)
750                 goto return_NULL;
751
752         MCOPY(&(gcstc->stb), stb, u1, gcstc_size);
753
754         /* release dump memory */
755
756         dump_release(dumpsize);
757
758         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
759                                                                    stacktrace_overhead)
760         return gcstc;
761
762 return_NULL:
763         dump_release(dumpsize);
764
765         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
766                                                                    stacktrace_overhead)
767
768         return NULL;
769 }
770
771
772 /* stacktrace_getClassContext **************************************************
773
774    Creates a Class context array.
775
776    RETURN VALUE:
777       the array of java.lang.Class objects, or
778           NULL if an exception has been thrown
779
780 *******************************************************************************/
781
782 java_handle_objectarray_t *stacktrace_getClassContext(void)
783 {
784         stacktracebuffer          *stb;
785         stacktrace_entry          *ste;
786         java_handle_objectarray_t *oa;
787         s4                         oalength;
788         s4                         i;
789         s4                         dumpsize;
790         CYCLES_STATS_DECLARE_AND_START
791
792         /* mark start of dump memory area */
793
794         dumpsize = dump_size();
795
796         /* create a stacktrace for the current thread */
797
798         stb = stacktrace_create(STACKFRAMEINFO);
799
800         if (stb == NULL)
801                 goto return_NULL;
802
803         /* calculate the size of the Class array */
804
805         for (i = 0, oalength = 0; i < stb->used; i++)
806                 if (stb->entries[i].method != NULL)
807                         oalength++;
808
809         /* The first entry corresponds to the method whose implementation */
810         /* calls stacktrace_getClassContext. We remove that entry.        */
811
812         ste = &(stb->entries[0]);
813         ste++;
814         oalength--;
815
816         /* allocate the Class array */
817
818         oa = builtin_anewarray(oalength, class_java_lang_Class);
819         if (!oa)
820                 goto return_NULL;
821
822         /* fill the Class array from the stacktracebuffer */
823
824         for(i = 0; i < oalength; i++, ste++) {
825                 if (ste->method == NULL) {
826                         i--;
827                         continue;
828                 }
829
830                 LLNI_array_direct(oa, i) = (java_object_t *) ste->method->class;
831         }
832
833         /* release dump memory */
834
835         dump_release(dumpsize);
836
837         CYCLES_STATS_END(stacktrace_getClassContext)
838
839         return oa;
840
841 return_NULL:
842         dump_release(dumpsize);
843
844         CYCLES_STATS_END(stacktrace_getClassContext)
845
846         return NULL;
847 }
848
849
850 /* stacktrace_getCurrentClass **************************************************
851
852    Find the current class by walking the stack trace.
853
854    Quote from the JNI documentation:
855          
856    In the Java 2 Platform, FindClass locates the class loader
857    associated with the current native method.  If the native code
858    belongs to a system class, no class loader will be
859    involved. Otherwise, the proper class loader will be invoked to
860    load and link the named class. When FindClass is called through the
861    Invocation Interface, there is no current native method or its
862    associated class loader. In that case, the result of
863    ClassLoader.getBaseClassLoader is used."
864
865 *******************************************************************************/
866
867 #if defined(ENABLE_JAVASE)
868 classinfo *stacktrace_getCurrentClass(void)
869 {
870         stacktracebuffer  *stb;
871         stacktrace_entry  *ste;
872         methodinfo        *m;
873         s4                 i;
874         s4                 dumpsize;
875         CYCLES_STATS_DECLARE_AND_START
876
877         /* mark start of dump memory area */
878
879         dumpsize = dump_size();
880
881         /* create a stacktrace for the current thread */
882
883         stb = stacktrace_create(STACKFRAMEINFO);
884
885         if (stb == NULL)
886                 goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
887
888         /* iterate over all stacktrace entries and find the first suitable
889            class */
890
891         for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
892                 m = ste->method;
893
894                 if (m == NULL)
895                         continue;
896
897                 if (m->class == class_java_security_PrivilegedAction)
898                         goto return_NULL;
899
900                 if (m->class != NULL) {
901                         dump_release(dumpsize);
902
903                         CYCLES_STATS_END(stacktrace_getCurrentClass)
904
905                         return m->class;
906                 }
907         }
908
909         /* no Java method found on the stack */
910
911 return_NULL:
912         dump_release(dumpsize);
913
914         CYCLES_STATS_END(stacktrace_getCurrentClass)
915
916         return NULL;
917 }
918 #endif /* ENABLE_JAVASE */
919
920
921 /* stacktrace_getStack *********************************************************
922
923    Create a 2-dimensional array for java.security.VMAccessControler.
924
925    RETURN VALUE:
926       the arrary, or
927           NULL if an exception has been thrown
928
929 *******************************************************************************/
930
931 #if defined(ENABLE_JAVASE)
932 java_handle_objectarray_t *stacktrace_getStack(void)
933 {
934         stacktracebuffer          *stb;
935         stacktrace_entry          *ste;
936         java_handle_objectarray_t *oa;
937         java_handle_objectarray_t *classes;
938         java_handle_objectarray_t *methodnames;
939         classinfo                 *c;
940         java_handle_t             *string;
941         s4                         i;
942         s4                         dumpsize;
943         CYCLES_STATS_DECLARE_AND_START
944
945         /* mark start of dump memory area */
946
947         dumpsize = dump_size();
948
949         /* create a stacktrace for the current thread */
950
951         stb = stacktrace_create(STACKFRAMEINFO);
952
953         if (stb == NULL)
954                 goto return_NULL;
955
956         /* get the first stacktrace entry */
957
958         ste = &(stb->entries[0]);
959
960         /* allocate all required arrays */
961
962         oa = builtin_anewarray(2, arrayclass_java_lang_Object);
963
964         if (oa == NULL)
965                 goto return_NULL;
966
967         classes = builtin_anewarray(stb->used, class_java_lang_Class);
968
969         if (classes == NULL)
970                 goto return_NULL;
971
972         methodnames = builtin_anewarray(stb->used, class_java_lang_String);
973
974         if (methodnames == NULL)
975                 goto return_NULL;
976
977         /* set up the 2-dimensional array */
978
979         LLNI_objectarray_element_set(oa, 0, classes);
980         LLNI_objectarray_element_set(oa, 1, methodnames);
981
982         /* iterate over all stacktrace entries */
983
984         for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
985                 c = ste->method->class;
986
987                 LLNI_array_direct(classes, i) = (java_object_t *) c;
988
989                 string = javastring_new(ste->method->name);
990
991                 if (string == NULL)
992                         goto return_NULL;
993
994                 LLNI_objectarray_element_set(methodnames, i, string);
995         }
996
997         /* return the 2-dimensional array */
998
999         dump_release(dumpsize);
1000
1001         CYCLES_STATS_END(stacktrace_getStack)
1002
1003         return oa;
1004
1005 return_NULL:
1006         dump_release(dumpsize);
1007
1008         CYCLES_STATS_END(stacktrace_getStack)
1009
1010         return NULL;
1011 }
1012 #endif /* ENABLE_JAVASE */
1013
1014
1015 /* stacktrace_print_trace_from_buffer ******************************************
1016
1017    Print the stacktrace of a given stacktracebuffer with CACAO intern
1018    methods (no Java help). This method is used by
1019    stacktrace_dump_trace and builtin_trace_exception.
1020
1021 *******************************************************************************/
1022
1023 void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
1024 {
1025         stacktrace_entry *ste;
1026         methodinfo       *m;
1027         s4                i;
1028
1029         ste = &(stb->entries[0]);
1030
1031         for (i = 0; i < stb->used; i++, ste++) {
1032                 m = ste->method;
1033
1034                 printf("\tat ");
1035                 utf_display_printable_ascii_classname(m->class->name);
1036                 printf(".");
1037                 utf_display_printable_ascii(m->name);
1038                 utf_display_printable_ascii(m->descriptor);
1039
1040                 if (m->flags & ACC_NATIVE) {
1041                         puts("(Native Method)");
1042
1043                 } else {
1044                         printf("(");
1045                         utf_display_printable_ascii(m->class->sourcefile);
1046                         printf(":%d)\n", (u4) ste->linenumber);
1047                 }
1048         }
1049
1050         /* just to be sure */
1051
1052         fflush(stdout);
1053 }
1054
1055
1056 /* stacktrace_print_trace ******************************************************
1057
1058    Print the stacktrace of a given exception. More or less a wrapper
1059    to stacktrace_print_trace_from_buffer.
1060
1061 *******************************************************************************/
1062
1063 void stacktrace_print_trace(java_handle_t *xptr)
1064 {
1065         java_lang_Throwable   *t;
1066 #if defined(WITH_CLASSPATH_GNU)
1067         java_lang_VMThrowable *vmt;
1068 #endif
1069         stacktracecontainer   *stc;
1070         stacktracebuffer      *stb;
1071
1072         t = (java_lang_Throwable *) xptr;
1073
1074         if (t == NULL)
1075                 return;
1076
1077         /* now print the stacktrace */
1078
1079 #if defined(WITH_CLASSPATH_GNU)
1080         LLNI_field_get_ref(t, vmState, vmt);
1081         stc = (stacktracecontainer *) LLNI_field_direct(vmt, vmData);
1082 #elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
1083         stc = (stacktracecontainer *) t->backtrace;
1084 #else
1085 # error unknown classpath configuration
1086 #endif
1087
1088         stb = &(stc->stb);
1089
1090         stacktrace_print_trace_from_buffer(stb);
1091 }
1092
1093
1094 #if defined(ENABLE_CYCLES_STATS)
1095 void stacktrace_print_cycles_stats(FILE *file)
1096 {
1097         CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
1098         CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
1099         CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
1100         CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
1101         CYCLES_STATS_PRINT(stacktrace_getStack        ,file);
1102 }
1103 #endif
1104
1105
1106 /*
1107  * These are local overrides for various environment variables in Emacs.
1108  * Please do not remove this and leave it at the end of the file, where
1109  * Emacs will automagically detect them.
1110  * ---------------------------------------------------------------------
1111  * Local variables:
1112  * mode: c
1113  * indent-tabs-mode: t
1114  * c-basic-offset: 4
1115  * tab-width: 4
1116  * End:
1117  * vim:noexpandtab:sw=4:ts=4:
1118  */