* Merged with default branch at rev 16f3633aaa5a.
[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 void stacktrace_add_entry(stacktracebuffer *stb, methodinfo *m, u2 line)
322 {
323         stacktrace_entry *ste;
324
325         /* check if we already reached the buffer capacity */
326
327         if (stb->used >= stb->capacity) {
328                 /* reallocate new memory */
329
330                 stb->entries = DMREALLOC(stb->entries, stacktrace_entry, stb->capacity,
331                                                                  stb->capacity + STACKTRACE_CAPACITY_INCREMENT);
332
333                 /* set new buffer capacity */
334
335                 stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
336         }
337
338         /* insert the current entry */
339
340         ste = &(stb->entries[stb->used]);
341
342         ste->method     = m;
343         ste->linenumber = line;
344
345         /* increase entries used count */
346
347         stb->used += 1;
348 }
349
350
351 /* stacktrace_add_method *******************************************************
352
353    Add stacktrace entries[1] for the given method to the stacktrace buffer.
354
355    IN:
356        stb.........stacktracebuffer to fill
357            m...........method for which entries should be created
358            pv..........pv of method
359            pc..........position of program counter within the method's code
360
361    OUT:
362        true, if stacktrace entries were successfully created, false otherwise.
363
364    [1] In case of inlined methods there may be more than one stacktrace
365        entry for a codegen-level method. (see doc/inlining_stacktrace.txt)
366
367 *******************************************************************************/
368
369 static bool stacktrace_add_method(stacktracebuffer *stb, methodinfo *m, u1 *pv,
370                                                                   u1 *pc)
371 {
372         codeinfo *code;                     /* compiled realization of method     */
373         s4        linenumber;
374
375         /* find the realization of the method the pc is in */
376
377         code = *((codeinfo **) (pv + CodeinfoPointer));
378
379         /* search the line number table */
380
381         linenumber = dseg_get_linenumber_from_pc(&m, pv, pc);
382
383         /* now add a new entry to the staktrace */
384
385         stacktrace_add_entry(stb, m, linenumber);
386
387         return true;
388 }
389
390
391 /* stacktrace_create ***********************************************************
392
393    Generates a stacktrace from the thread passed into a
394    stacktracebuffer.  The stacktracebuffer is allocated on the
395    dump memory.
396    
397    NOTE: The first element in the stackframe chain must always be a
398          native stackframeinfo (e.g. VMThrowable.fillInStackTrace() is
399          a native function).
400
401    RETURN VALUE:
402       pointer to the stacktracebuffer, or
403       NULL if there is no stacktrace available for the
404       given thread.
405
406 *******************************************************************************/
407
408 stacktracebuffer *stacktrace_create(stackframeinfo *sfi)
409 {
410         stacktracebuffer *stb;
411         methodinfo       *m;
412         codeinfo         *code;
413         u1               *pv;
414         u1               *sp;
415         u4                framesize;
416         u1               *ra;
417         u1               *xpc;
418
419         /* prevent compiler warnings */
420
421         pv = NULL;
422         sp = NULL;
423         ra = NULL;
424
425         /* create a stacktracebuffer in dump memory */
426
427         stb = DNEW(stacktracebuffer);
428
429         stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
430         stb->used     = 0;
431         stb->entries  = DMNEW(stacktrace_entry, STACKTRACE_CAPACITY_DEFAULT);
432
433 #define PRINTMETHODS 0
434
435 #if PRINTMETHODS
436         printf("\n\nfillInStackTrace start:\n");
437         fflush(stdout);
438 #endif
439
440         /* Loop while we have a method pointer (asm_calljavafunction has
441            NULL) or there is a stackframeinfo in the chain. */
442
443         m = NULL;
444
445         while ((m != NULL) || (sfi != NULL)) {
446                 /* m == NULL should only happen for the first time and inline
447                    stackframe infos, like from the exception stubs or the
448                    patcher wrapper. */
449
450                 if (m == NULL) {
451                         /* for native stub stackframe infos, pv is always NULL */
452
453                         if (sfi->pv == NULL) {
454                                 /* get methodinfo, sp and ra from the current stackframe info */
455
456                                 m  = sfi->method;
457                                 sp = sfi->sp;           /* sp of parent Java function         */
458                                 ra = sfi->ra;
459
460                                 if (m)
461                                         stacktrace_add_entry(stb, m, 0);
462
463 #if PRINTMETHODS
464                                 printf("ra=%p sp=%p, ", ra, sp);
465                                 method_print(m);
466                                 printf(": native stub\n");
467                                 fflush(stdout);
468 #endif
469                                 /* This is an native stub stackframe info, so we can
470                                    get the parent pv from the return address
471                                    (ICMD_INVOKE*). */
472
473 #if defined(ENABLE_INTRP)
474                                 if (opt_intrp)
475                                         pv = codegen_get_pv_from_pc(ra);
476                                 else
477 #endif
478                                         {
479 #if defined(ENABLE_JIT)
480                                                 pv = md_codegen_get_pv_from_pc(ra);
481 #endif
482                                         }
483
484                                 /* get methodinfo pointer from parent data segment */
485
486                                 code = *((codeinfo **) (pv + CodeinfoPointer));
487
488                                 /* For asm_vm_call_method the codeinfo pointer is
489                                    NULL. */
490
491                                 m = (code == NULL) ? NULL : code->m;
492
493                         } else {
494                                 /* Inline stackframe infos are special: they have a
495                                    xpc of the actual exception position and the return
496                                    address saved since an inline stackframe info can
497                                    also be in a leaf method (no return address saved
498                                    on stack!!!).  ATTENTION: This one is also for
499                                    hardware exceptions!!! */
500
501                                 /* get methodinfo, sp and ra from the current stackframe info */
502
503                                 m   = sfi->method;      /* m == NULL                          */
504                                 pv  = sfi->pv;          /* pv of parent Java function         */
505                                 sp  = sfi->sp;          /* sp of parent Java function         */
506                                 ra  = sfi->ra;          /* ra of parent Java function         */
507                                 xpc = sfi->xpc;         /* actual exception position          */
508
509 #if PRINTMETHODS
510                                 printf("ra=%p sp=%p, ", ra, sp);
511                                 printf("NULL: inline stub\n");
512                                 fflush(stdout);
513 #endif
514
515                                 /* get methodinfo from current Java method */
516
517                                 code = *((codeinfo **) (pv + CodeinfoPointer));
518
519                                 /* For asm_vm_call_method the codeinfo pointer is
520                                    NULL. */
521
522                                 m = (code == NULL) ? NULL : code->m;
523
524                                 /* if m == NULL, this is a asm_calljavafunction call */
525
526                                 if (m != NULL) {
527 #if PRINTMETHODS
528                                         printf("ra=%p sp=%p, ", ra, sp);
529                                         method_print(m);
530                                         printf(": inline stub parent");
531                                         fflush(stdout);
532 #endif
533
534 #if defined(ENABLE_INTRP)
535                                         if (!opt_intrp) {
536 #endif
537
538                                         /* add the method to the stacktrace */
539
540                                         stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) xpc));
541
542                                         /* get the current stack frame size */
543
544                                         framesize = *((u4 *) (pv + FrameSize));
545
546 #if PRINTMETHODS
547                                         printf(", framesize=%d\n", framesize);
548                                         fflush(stdout);
549 #endif
550
551                                         /* Set stack pointer to stackframe of parent Java
552                                            function of the current Java function. */
553
554 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
555                                         sp += framesize + SIZEOF_VOID_P;
556 #elif defined(__SPARC_64__)
557                                         sp = md_get_framepointer(sp);
558 #else
559                                         sp += framesize;
560 #endif
561
562                                         /* get data segment and methodinfo pointer from
563                                            parent method */
564
565 #if defined(ENABLE_JIT)
566                                         pv = md_codegen_get_pv_from_pc(ra);
567 #endif
568
569                                         code = *((codeinfo **) (pv + CodeinfoPointer));
570
571                                         /* For asm_vm_call_method the codeinfo pointer is
572                                            NULL. */
573
574                                         m = (code == NULL) ? NULL : code->m;
575
576 #if defined(ENABLE_INTRP)
577                                         }
578 #endif
579                                 }
580 #if PRINTMETHODS
581                                 else {
582                                         printf("ra=%p sp=%p, ", ra, sp);
583                                         printf("asm_calljavafunction\n");
584                                         fflush(stdout);
585                                 }
586 #endif
587                         }
588
589                         /* get previous stackframeinfo in the chain */
590
591                         sfi = sfi->prev;
592
593                 } else {
594 #if PRINTMETHODS
595                         printf("ra=%p sp=%p, ", ra, sp);
596                         method_print(m);
597                         printf(": JIT");
598                         fflush(stdout);
599 #endif
600
601                         /* JIT method found, add it to the stacktrace (we subtract
602                            1 from the return address since it points the the
603                            instruction after call). */
604
605                         stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1);
606
607                         /* get the current stack frame size */
608
609                         framesize = *((u4 *) (pv + FrameSize));
610
611 #if PRINTMETHODS
612                         printf(", framesize=%d\n", framesize);
613                         fflush(stdout);
614 #endif
615
616                         /* get return address of current stack frame */
617
618 #if defined(ENABLE_JIT)
619 # if defined(ENABLE_INTRP)
620                         if (opt_intrp)
621                                 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
622                         else
623 # endif
624                                 ra = md_stacktrace_get_returnaddress(sp, framesize);
625 #else
626                         ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
627 #endif
628
629                         /* get data segment and methodinfo pointer from parent method */
630
631 #if defined(ENABLE_INTRP)
632                         if (opt_intrp)
633                                 pv = codegen_get_pv_from_pc(ra);
634                         else
635 #endif
636                                 {
637 #if defined(ENABLE_JIT)
638 # if defined(__SPARC_64__)
639                                         sp = md_get_framepointer(sp);
640                                         pv = md_get_pv_from_stackframe(sp);
641 # else
642                                         pv = md_codegen_get_pv_from_pc(ra);
643 # endif
644 #endif
645                                 }
646
647                         code = *((codeinfo **) (pv + CodeinfoPointer));
648
649                         /* For asm_vm_call_method the codeinfo pointer is NULL. */
650
651                         m = (code == NULL) ? NULL : code->m;
652
653                         /* walk the stack */
654
655 #if defined(ENABLE_INTRP)
656                         if (opt_intrp)
657                                 sp = *(u1 **) (sp - framesize);
658                         else
659 #endif
660                                 {
661 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
662                                         sp += framesize + SIZEOF_VOID_P;
663 #elif defined(__SPARC_64__)
664                                         /* already has the new sp */
665 #else
666                                         sp += framesize;
667 #endif
668                                 }
669                 }
670         }
671
672         /* return the stacktracebuffer */
673
674         if (stb->used == 0)
675                 return NULL;
676         else
677                 return stb;
678 }
679
680
681 /* stacktrace_fillInStackTrace *************************************************
682
683    Generate a stacktrace from the current thread for
684    java.lang.VMThrowable.fillInStackTrace.
685
686 *******************************************************************************/
687
688 stacktracecontainer *stacktrace_fillInStackTrace(void)
689 {
690         stacktracebuffer    *stb;
691         stacktracecontainer *gcstc;
692         s4                   gcstc_size;
693         s4                   dumpsize;
694         CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
695
696         /* mark start of dump memory area */
697
698         dumpsize = dump_size();
699
700         /* create a stacktrace from the current thread */
701
702         stb = stacktrace_create(STACKFRAMEINFO);
703
704         if (stb == NULL)
705                 goto return_NULL;
706
707         /* allocate memory from the GC heap and copy the stacktrace buffer */
708         /* ATTENTION: use stacktracecontainer for this and make it look like
709        an array */
710
711         gcstc_size = sizeof(stacktracebuffer) +
712                      sizeof(stacktrace_entry) * stb->used;
713         gcstc = (stacktracecontainer *) builtin_newarray_byte(gcstc_size);
714
715         if (gcstc == NULL)
716                 goto return_NULL;
717
718         gcstc->stb.capacity = stb->capacity;
719         gcstc->stb.used     = stb->used;
720         gcstc->stb.entries  = gcstc->data;
721
722         MCOPY(gcstc->data, stb->entries, stacktrace_entry, stb->used);
723
724         /* release dump memory */
725
726         dump_release(dumpsize);
727
728         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
729                                                                    stacktrace_overhead)
730         return gcstc;
731
732 return_NULL:
733         dump_release(dumpsize);
734
735         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
736                                                                    stacktrace_overhead)
737
738         return NULL;
739 }
740
741
742 /* stacktrace_getClassContext **************************************************
743
744    Creates a Class context array.
745
746    RETURN VALUE:
747       the array of java.lang.Class objects, or
748           NULL if an exception has been thrown
749
750 *******************************************************************************/
751
752 java_handle_objectarray_t *stacktrace_getClassContext(void)
753 {
754         stacktracebuffer          *stb;
755         stacktrace_entry          *ste;
756         java_handle_objectarray_t *oa;
757         s4                         oalength;
758         s4                         i;
759         s4                         dumpsize;
760         CYCLES_STATS_DECLARE_AND_START
761
762         /* mark start of dump memory area */
763
764         dumpsize = dump_size();
765
766         /* create a stacktrace for the current thread */
767
768         stb = stacktrace_create(STACKFRAMEINFO);
769
770         if (stb == NULL)
771                 goto return_NULL;
772
773         /* calculate the size of the Class array */
774
775         for (i = 0, oalength = 0; i < stb->used; i++)
776                 if (stb->entries[i].method != NULL)
777                         oalength++;
778
779         /* The first entry corresponds to the method whose implementation */
780         /* calls stacktrace_getClassContext. We remove that entry.        */
781
782         ste = &(stb->entries[0]);
783         ste++;
784         oalength--;
785
786         /* allocate the Class array */
787
788         oa = builtin_anewarray(oalength, class_java_lang_Class);
789         if (!oa)
790                 goto return_NULL;
791
792         /* fill the Class array from the stacktracebuffer */
793
794         for(i = 0; i < oalength; i++, ste++) {
795                 if (ste->method == NULL) {
796                         i--;
797                         continue;
798                 }
799
800                 oa->data[i] = (java_object_t *) ste->method->class;
801         }
802
803         /* release dump memory */
804
805         dump_release(dumpsize);
806
807         CYCLES_STATS_END(stacktrace_getClassContext)
808
809         return oa;
810
811 return_NULL:
812         dump_release(dumpsize);
813
814         CYCLES_STATS_END(stacktrace_getClassContext)
815
816         return NULL;
817 }
818
819
820 /* stacktrace_getCurrentClass **************************************************
821
822    Find the current class by walking the stack trace.
823
824    Quote from the JNI documentation:
825          
826    In the Java 2 Platform, FindClass locates the class loader
827    associated with the current native method.  If the native code
828    belongs to a system class, no class loader will be
829    involved. Otherwise, the proper class loader will be invoked to
830    load and link the named class. When FindClass is called through the
831    Invocation Interface, there is no current native method or its
832    associated class loader. In that case, the result of
833    ClassLoader.getBaseClassLoader is used."
834
835 *******************************************************************************/
836
837 #if defined(ENABLE_JAVASE)
838 classinfo *stacktrace_getCurrentClass(void)
839 {
840         stacktracebuffer  *stb;
841         stacktrace_entry  *ste;
842         methodinfo        *m;
843         s4                 i;
844         s4                 dumpsize;
845         CYCLES_STATS_DECLARE_AND_START
846
847         /* mark start of dump memory area */
848
849         dumpsize = dump_size();
850
851         /* create a stacktrace for the current thread */
852
853         stb = stacktrace_create(STACKFRAMEINFO);
854
855         if (stb == NULL)
856                 goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
857
858         /* iterate over all stacktrace entries and find the first suitable
859            class */
860
861         for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
862                 m = ste->method;
863
864                 if (m == NULL)
865                         continue;
866
867                 if (m->class == class_java_security_PrivilegedAction)
868                         goto return_NULL;
869
870                 if (m->class != NULL) {
871                         dump_release(dumpsize);
872
873                         CYCLES_STATS_END(stacktrace_getCurrentClass)
874
875                         return m->class;
876                 }
877         }
878
879         /* no Java method found on the stack */
880
881 return_NULL:
882         dump_release(dumpsize);
883
884         CYCLES_STATS_END(stacktrace_getCurrentClass)
885
886         return NULL;
887 }
888 #endif /* ENABLE_JAVASE */
889
890
891 /* stacktrace_getStack *********************************************************
892
893    Create a 2-dimensional array for java.security.VMAccessControler.
894
895    RETURN VALUE:
896       the arrary, or
897           NULL if an exception has been thrown
898
899 *******************************************************************************/
900
901 #if defined(ENABLE_JAVASE)
902 java_handle_objectarray_t *stacktrace_getStack(void)
903 {
904         stacktracebuffer          *stb;
905         stacktrace_entry          *ste;
906         java_handle_objectarray_t *oa;
907         java_handle_objectarray_t *classes;
908         java_handle_objectarray_t *methodnames;
909         classinfo                 *c;
910         java_handle_t             *string;
911         s4                         i;
912         s4                         dumpsize;
913         CYCLES_STATS_DECLARE_AND_START
914
915         /* mark start of dump memory area */
916
917         dumpsize = dump_size();
918
919         /* create a stacktrace for the current thread */
920
921         stb = stacktrace_create(STACKFRAMEINFO);
922
923         if (stb == NULL)
924                 goto return_NULL;
925
926         /* get the first stacktrace entry */
927
928         ste = &(stb->entries[0]);
929
930         /* allocate all required arrays */
931
932         oa = builtin_anewarray(2, arrayclass_java_lang_Object);
933
934         if (oa == NULL)
935                 goto return_NULL;
936
937         classes = builtin_anewarray(stb->used, class_java_lang_Class);
938
939         if (classes == NULL)
940                 goto return_NULL;
941
942         methodnames = builtin_anewarray(stb->used, class_java_lang_String);
943
944         if (methodnames == NULL)
945                 goto return_NULL;
946
947         /* set up the 2-dimensional array */
948
949         oa->data[0] = (java_object_t *) classes;
950         oa->data[1] = (java_object_t *) methodnames;
951
952         /* iterate over all stacktrace entries */
953
954         for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
955                 c = ste->method->class;
956
957                 classes->data[i] = (java_object_t *) c;
958
959                 string = javastring_new(ste->method->name);
960
961                 if (string == NULL)
962                         goto return_NULL;
963
964                 methodnames->data[i] = string;
965         }
966
967         /* return the 2-dimensional array */
968
969         dump_release(dumpsize);
970
971         CYCLES_STATS_END(stacktrace_getStack)
972
973         return oa;
974
975 return_NULL:
976         dump_release(dumpsize);
977
978         CYCLES_STATS_END(stacktrace_getStack)
979
980         return NULL;
981 }
982 #endif /* ENABLE_JAVASE */
983
984
985 /* stacktrace_print_trace_from_buffer ******************************************
986
987    Print the stacktrace of a given stacktracebuffer with CACAO intern
988    methods (no Java help). This method is used by
989    stacktrace_dump_trace and builtin_trace_exception.
990
991 *******************************************************************************/
992
993 void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
994 {
995         stacktrace_entry *ste;
996         methodinfo       *m;
997         s4                i;
998
999         ste = &(stb->entries[0]);
1000
1001         for (i = 0; i < stb->used; i++, ste++) {
1002                 m = ste->method;
1003
1004                 printf("\tat ");
1005                 utf_display_printable_ascii_classname(m->class->name);
1006                 printf(".");
1007                 utf_display_printable_ascii(m->name);
1008                 utf_display_printable_ascii(m->descriptor);
1009
1010                 if (m->flags & ACC_NATIVE) {
1011                         puts("(Native Method)");
1012
1013                 } else {
1014                         printf("(");
1015                         utf_display_printable_ascii(m->class->sourcefile);
1016                         printf(":%d)\n", (u4) ste->linenumber);
1017                 }
1018         }
1019
1020         /* just to be sure */
1021
1022         fflush(stdout);
1023 }
1024
1025
1026 /* stacktrace_print_trace ******************************************************
1027
1028    Print the stacktrace of a given exception. More or less a wrapper
1029    to stacktrace_print_trace_from_buffer.
1030
1031 *******************************************************************************/
1032
1033 void stacktrace_print_trace(java_handle_t *xptr)
1034 {
1035         java_lang_Throwable   *t;
1036 #if defined(WITH_CLASSPATH_GNU)
1037         java_lang_VMThrowable *vmt;
1038 #endif
1039         stacktracecontainer   *stc;
1040         stacktracebuffer      *stb;
1041
1042         t = (java_lang_Throwable *) xptr;
1043
1044         if (t == NULL)
1045                 return;
1046
1047         /* now print the stacktrace */
1048
1049 #if defined(WITH_CLASSPATH_GNU)
1050         LLNI_field_get_ref(t, vmState, vmt);
1051         stc = (stacktracecontainer *) LLNI_field_direct(vmt, vmData);
1052 #elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
1053         stc = (stacktracecontainer *) t->backtrace;
1054 #else
1055 # error unknown classpath configuration
1056 #endif
1057
1058         stb = &(stc->stb);
1059
1060         stacktrace_print_trace_from_buffer(stb);
1061 }
1062
1063
1064 #if defined(ENABLE_CYCLES_STATS)
1065 void stacktrace_print_cycles_stats(FILE *file)
1066 {
1067         CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
1068         CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
1069         CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
1070         CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
1071         CYCLES_STATS_PRINT(stacktrace_getStack        ,file);
1072 }
1073 #endif
1074
1075
1076 /*
1077  * These are local overrides for various environment variables in Emacs.
1078  * Please do not remove this and leave it at the end of the file, where
1079  * Emacs will automagically detect them.
1080  * ---------------------------------------------------------------------
1081  * Local variables:
1082  * mode: c
1083  * indent-tabs-mode: t
1084  * c-basic-offset: 4
1085  * tab-width: 4
1086  * End:
1087  * vim:noexpandtab:sw=4:ts=4:
1088  */