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