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