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