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