This commit introduces C++ wrapper classes for Java heap objects.
[cacao.git] / src / vm / jit / stacktrace.cpp
1 /* src/vm/jit/stacktrace.cpp - machine independent stacktrace system
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <assert.h>
29 #include <stdint.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "vm/types.h"
34
35 #include "md.h"
36
37 #include "mm/gc.hpp"
38 #include "mm/memory.h"
39
40 #include "vm/jit/stacktrace.hpp"
41
42 #include "vm/global.h"                   /* required here for native includes */
43 #include "native/jni.h"
44 #include "native/llni.h"
45
46 #include "threads/thread.hpp"
47
48 #include "toolbox/logging.h"
49
50 #include "vm/array.h"
51 #include "vm/builtin.h"
52 #include "vm/cycles-stats.h"
53 #include "vm/exceptions.hpp"
54 #include "vm/string.hpp"
55 #include "vm/vm.hpp"
56
57 #include "vm/jit/asmpart.h"
58 #include "vm/jit/codegen-common.h"
59 #include "vm/jit/linenumbertable.h"
60 #include "vm/jit/methodheader.h"
61 #include "vm/jit/methodtree.h"
62
63 #include "vmcore/class.h"
64 #include "vmcore/globals.hpp"
65 #include "vmcore/javaobjects.hpp"
66 #include "vmcore/loader.h"
67 #include "vmcore/method.h"
68 #include "vmcore/options.h"
69
70
71 // FIXME Use C-linkage for now.
72 extern "C" {
73
74 /* global variables ***********************************************************/
75
76 CYCLES_STATS_DECLARE(stacktrace_overhead        , 100, 1)
77 CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace, 40,  5000)
78 CYCLES_STATS_DECLARE(stacktrace_get,              40,  5000)
79 CYCLES_STATS_DECLARE(stacktrace_getClassContext , 40,  5000)
80 CYCLES_STATS_DECLARE(stacktrace_getCurrentClass , 40,  5000)
81 CYCLES_STATS_DECLARE(stacktrace_get_stack       , 40,  10000)
82
83
84 /* stacktrace_stackframeinfo_add ***********************************************
85
86    Fills a stackframe info structure with the given or calculated
87    values and adds it to the chain.
88
89 *******************************************************************************/
90
91 void stacktrace_stackframeinfo_add(stackframeinfo_t* sfi, void* pv, void* sp, void* ra, void* xpc)
92 {
93         stackframeinfo_t *currentsfi;
94         codeinfo         *code;
95 #if defined(ENABLE_JIT)
96         s4                 framesize;
97 #endif
98
99         /* Get current stackframe info. */
100
101         currentsfi = threads_get_current_stackframeinfo();
102
103         /* sometimes we don't have pv handy (e.g. in asmpart.S:
104        L_asm_call_jit_compiler_exception or in the interpreter). */
105
106         if (pv == NULL) {
107 #if defined(ENABLE_INTRP)
108                 if (opt_intrp)
109                         pv = methodtree_find(ra);
110                 else
111 #endif
112                         {
113 #if defined(ENABLE_JIT)
114 # if defined(__SPARC_64__)
115                                 pv = md_get_pv_from_stackframe(sp);
116 # else
117                                 pv = md_codegen_get_pv_from_pc(ra);
118 # endif
119 #endif
120                         }
121         }
122
123         /* Get codeinfo pointer for the parent Java method. */
124
125         code = code_get_codeinfo_for_pv(pv);
126
127         /* XXX */
128         /*      assert(m != NULL); */
129
130 #if defined(ENABLE_JIT)
131 # if defined(ENABLE_INTRP)
132         /* When using the interpreter, we pass RA to the function. */
133
134         if (!opt_intrp) {
135 # endif
136 # if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__M68K__)
137                 /* On i386 and x86_64 we always have to get the return address
138                    from the stack. */
139                 /* m68k has return address on stack always */
140                 /* On S390 we use REG_RA as REG_ITMP3, so we have always to get
141                    the RA from stack. */
142
143                 framesize = *((u4 *) (((uintptr_t) pv) + FrameSize));
144
145                 ra = md_stacktrace_get_returnaddress(sp, framesize);
146 # else
147                 /* If the method is a non-leaf function, we need to get the
148                    return address from the stack.  For leaf functions the
149                    return address is set correctly.  This makes the assembler
150                    and the signal handler code simpler.  The code is NULL is
151                    the asm_vm_call_method special case. */
152
153                 if ((code == NULL) || !code_is_leafmethod(code)) {
154                         framesize = *((u4 *) (((uintptr_t) pv) + FrameSize));
155
156                         ra = md_stacktrace_get_returnaddress(sp, framesize);
157                 }
158 # endif
159 # if defined(ENABLE_INTRP)
160         }
161 # endif
162 #endif
163
164         /* Calculate XPC when not given.  The XPC is then the return
165            address of the current method minus 1 because the RA points to
166            the instruction after the call instruction.  This is required
167            e.g. for method stubs. */
168
169         if (xpc == NULL) {
170                 xpc = (void *) (((intptr_t) ra) - 1);
171         }
172
173         /* Fill new stackframeinfo structure. */
174
175         sfi->prev = currentsfi;
176         sfi->code = code;
177         sfi->pv   = pv;
178         sfi->sp   = sp;
179         sfi->ra   = ra;
180         sfi->xpc  = xpc;
181
182 #if !defined(NDEBUG)
183         if (opt_DebugStackFrameInfo) {
184                 log_start();
185                 log_print("[stackframeinfo add   : sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
186                                   sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
187                 method_print(sfi->code->m);
188                 log_print("]");
189                 log_finish();
190         }
191 #endif
192
193         /* Store new stackframeinfo pointer. */
194
195         threads_set_current_stackframeinfo(sfi);
196
197         /* set the native world flag for the current thread */
198         /* ATTENTION: This flag tells the GC how to treat this thread in case of
199            a collection. Set this flag _after_ a valid stackframe info was set. */
200
201         THREAD_NATIVEWORLD_ENTER;
202 }
203
204
205 /* stacktrace_stackframeinfo_remove ********************************************
206
207    Remove the given stackframeinfo from the chain in the current
208    thread.
209
210 *******************************************************************************/
211
212 void stacktrace_stackframeinfo_remove(stackframeinfo_t *sfi)
213 {
214         /* Clear the native world flag for the current thread. */
215         /* ATTENTION: Clear this flag _before_ removing the stackframe info. */
216
217         THREAD_NATIVEWORLD_EXIT;
218
219 #if !defined(NDEBUG)
220         if (opt_DebugStackFrameInfo) {
221                 log_start();
222                 log_print("[stackframeinfo remove: sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
223                                   sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
224                 method_print(sfi->code->m);
225                 log_print("]");
226                 log_finish();
227         }
228 #endif
229
230         /* Set previous stackframe info. */
231
232         threads_set_current_stackframeinfo(sfi->prev);
233 }
234
235
236 /* stacktrace_stackframeinfo_fill **********************************************
237
238    Fill the temporary stackframeinfo structure with the values given
239    in sfi.
240
241    IN:
242        tmpsfi ... temporary stackframeinfo
243        sfi ...... stackframeinfo to be used in the next iteration
244
245 *******************************************************************************/
246
247 static inline void stacktrace_stackframeinfo_fill(stackframeinfo_t *tmpsfi, stackframeinfo_t *sfi)
248 {
249         /* Sanity checks. */
250
251         assert(tmpsfi != NULL);
252         assert(sfi != NULL);
253
254         /* Fill the temporary stackframeinfo. */
255
256         tmpsfi->code = sfi->code;
257         tmpsfi->pv   = sfi->pv;
258         tmpsfi->sp   = sfi->sp;
259         tmpsfi->ra   = sfi->ra;
260         tmpsfi->xpc  = sfi->xpc;
261
262         /* Set the previous stackframe info of the temporary one to the
263            next in the chain. */
264
265         tmpsfi->prev = sfi->prev;
266
267 #if !defined(NDEBUG)
268         if (opt_DebugStackTrace)
269                 log_println("[stacktrace fill]");
270 #endif
271 }
272
273
274 /* stacktrace_stackframeinfo_next **********************************************
275
276    Walk the stack (or the stackframeinfo-chain) to the next method and
277    return the new stackframe values in the temporary stackframeinfo
278    passed.
279
280    ATTENTION: This function does NOT skip builtin methods!
281
282    IN:
283        tmpsfi ... temporary stackframeinfo of current method
284
285 *******************************************************************************/
286
287 static inline void stacktrace_stackframeinfo_next(stackframeinfo_t *tmpsfi)
288 {
289         codeinfo         *code;
290         void             *pv;
291         void             *sp;
292         void             *ra;
293         void             *xpc;
294         uint32_t          framesize;
295         stackframeinfo_t *prevsfi;
296
297         /* Sanity check. */
298
299         assert(tmpsfi != NULL);
300
301         /* Get values from the stackframeinfo. */
302
303         code = tmpsfi->code;
304         pv   = tmpsfi->pv;
305         sp   = tmpsfi->sp;
306         ra   = tmpsfi->ra;
307         xpc  = tmpsfi->xpc;
308  
309         /* Get the current stack frame size. */
310
311         framesize = *((uint32_t *) (((intptr_t) pv) + FrameSize));
312
313         /* Get the RA of the current stack frame (RA to the parent Java
314            method) if the current method is a non-leaf method.  Otherwise
315            the value in the stackframeinfo is correct (from the signal
316            handler). */
317
318 #if defined(ENABLE_JIT)
319 # if defined(ENABLE_INTRP)
320         if (opt_intrp)
321                 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
322         else
323 # endif
324                 {
325                         if (!code_is_leafmethod(code))
326                                 ra = md_stacktrace_get_returnaddress(sp, framesize);
327                 }
328 #else
329         ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
330 #endif
331
332         /* Get the PV for the parent Java method. */
333
334 #if defined(ENABLE_INTRP)
335         if (opt_intrp)
336                 pv = methodtree_find(ra);
337         else
338 #endif
339                 {
340 #if defined(ENABLE_JIT)
341 # if defined(__SPARC_64__)
342                         sp = md_get_framepointer(sp);
343                         pv = md_get_pv_from_stackframe(sp);
344 # else
345                         pv = md_codegen_get_pv_from_pc(ra);
346 # endif
347 #endif
348                 }
349
350         /* Get the codeinfo pointer for the parent Java method. */
351
352         code = code_get_codeinfo_for_pv(pv);
353
354         /* Calculate the SP for the parent Java method. */
355
356 #if defined(ENABLE_INTRP)
357         if (opt_intrp)
358                 sp = *(u1 **) (sp - framesize);
359         else
360 #endif
361                 {
362 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
363                         sp = (void *) (((intptr_t) sp) + framesize + SIZEOF_VOID_P);
364 #elif defined(__SPARC_64__)
365                         /* already has the new sp */
366 #else
367                         sp = (void *) (((intptr_t) sp) + framesize);
368 #endif
369                 }
370
371         /* If the new codeinfo pointer is NULL we reached a
372            asm_vm_call_method function.  In this case we get the next
373            values from the previous stackframeinfo in the chain.
374            Otherwise the new values have been calculated before. */
375
376         if (code == NULL) {
377                 prevsfi = tmpsfi->prev;
378
379                 /* If the previous stackframeinfo in the chain is NULL we
380                    reached the top of the stacktrace.  We set code and prev to
381                    NULL to mark the end, which is checked in
382                    stacktrace_stackframeinfo_end_check. */
383
384                 if (prevsfi == NULL) {
385                         tmpsfi->code = NULL;
386                         tmpsfi->prev = NULL;
387                         return;
388                 }
389
390                 /* Fill the temporary stackframeinfo with the new values. */
391
392                 stacktrace_stackframeinfo_fill(tmpsfi, prevsfi);
393         }
394         else {
395                 /* Store the new values in the stackframeinfo.  NOTE: We
396                    subtract 1 from the RA to get the XPC, because the RA
397                    points to the instruction after the call instruction. */
398
399                 tmpsfi->code = code;
400                 tmpsfi->pv   = pv;
401                 tmpsfi->sp   = sp;
402                 tmpsfi->ra   = ra;
403                 tmpsfi->xpc  = (void *) (((intptr_t) ra) - 1);
404         }
405
406 #if !defined(NDEBUG)
407         /* Print current method information. */
408
409         if (opt_DebugStackTrace) {
410                 log_start();
411                 log_print("[stacktrace: method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
412                                   tmpsfi->code->m, tmpsfi->pv, tmpsfi->sp, tmpsfi->ra,
413                                   tmpsfi->xpc);
414                 method_print(tmpsfi->code->m);
415                 log_print("]");
416                 log_finish();
417         }
418 #endif
419 }
420
421
422 /* stacktrace_stackframeinfo_end_check *****************************************
423
424    Check if we reached the end of the stacktrace.
425
426    IN:
427        tmpsfi ... temporary stackframeinfo of current method
428
429    RETURN:
430        true .... the end is reached
431            false ... the end is not reached
432
433 *******************************************************************************/
434
435 static inline bool stacktrace_stackframeinfo_end_check(stackframeinfo_t *tmpsfi)
436 {
437         /* Sanity check. */
438
439         assert(tmpsfi != NULL);
440
441         if ((tmpsfi->code == NULL) && (tmpsfi->prev == NULL)) {
442 #if !defined(NDEBUG)
443                 if (opt_DebugStackTrace)
444                         log_println("[stacktrace stop]");
445 #endif
446
447                 return true;
448         }
449
450         return false;
451 }
452
453
454 /* stacktrace_depth ************************************************************
455
456    Calculates and returns the depth of the current stacktrace.
457
458    IN:
459        sfi ... stackframeinfo where to start the stacktrace
460
461    RETURN:
462        depth of the stacktrace
463
464 *******************************************************************************/
465
466 static int stacktrace_depth(stackframeinfo_t *sfi)
467 {
468         stackframeinfo_t  tmpsfi;
469         int               depth;
470         methodinfo       *m;
471
472 #if !defined(NDEBUG)
473         if (opt_DebugStackTrace)
474                 log_println("[stacktrace_depth]");
475 #endif
476
477         /* XXX This is not correct, but a workaround for threads-dump for
478            now. */
479 /*      assert(sfi != NULL); */
480         if (sfi == NULL)
481                 return 0;
482
483         /* Iterate over all stackframes. */
484
485         depth = 0;
486
487         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
488                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
489                  stacktrace_stackframeinfo_next(&tmpsfi)) {
490                 /* Get methodinfo. */
491
492                 m = tmpsfi.code->m;
493
494                 /* Skip builtin methods. */
495
496                 if (m->flags & ACC_METHOD_BUILTIN)
497                         continue;
498
499                 depth++;
500         }
501
502         return depth;
503 }
504
505
506 /* stacktrace_get **************************************************************
507
508    Builds and returns a stacktrace starting from the given stackframe
509    info and returns the stacktrace structure wrapped in a Java
510    byte-array to not confuse the GC.
511
512    IN:
513        sfi ... stackframe info to start stacktrace from
514
515    RETURN:
516        stacktrace as Java byte-array
517
518 *******************************************************************************/
519
520 java_handle_bytearray_t *stacktrace_get(stackframeinfo_t *sfi)
521 {
522         stackframeinfo_t         tmpsfi;
523         int                      depth;
524         java_handle_bytearray_t *ba;
525         int32_t                  ba_size;
526         stacktrace_t            *st;
527         stacktrace_entry_t      *ste;
528         methodinfo              *m;
529         bool                     skip_fillInStackTrace;
530         bool                     skip_init;
531
532         CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
533
534 #if !defined(NDEBUG)
535         if (opt_DebugStackTrace)
536                 log_println("[stacktrace_get]");
537 #endif
538
539         skip_fillInStackTrace = true;
540         skip_init             = true;
541
542         depth = stacktrace_depth(sfi);
543
544         if (depth == 0)
545                 return NULL;
546
547         /* Allocate memory from the GC heap and copy the stacktrace
548            buffer. */
549         /* ATTENTION: Use a Java byte-array for this to not confuse the
550            GC. */
551         /* FIXME: We waste some memory here as we skip some entries
552            later. */
553
554         ba_size = sizeof(stacktrace_t) + sizeof(stacktrace_entry_t) * depth;
555
556         ba = builtin_newarray_byte(ba_size);
557
558         if (ba == NULL)
559                 goto return_NULL;
560
561         /* Get a stacktrace entry pointer. */
562         /* ATTENTION: We need a critical section here because we use the
563            byte-array data pointer directly. */
564
565         LLNI_CRITICAL_START;
566
567         st = (stacktrace_t *) LLNI_array_data(ba);
568
569         ste = st->entries;
570
571         /* Iterate over the whole stack. */
572
573         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
574                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
575                  stacktrace_stackframeinfo_next(&tmpsfi)) {
576                 /* Get the methodinfo. */
577
578                 m = tmpsfi.code->m;
579
580                 /* Skip builtin methods. */
581
582                 if (m->flags & ACC_METHOD_BUILTIN)
583                         continue;
584
585                 /* This logic is taken from
586                    hotspot/src/share/vm/classfile/javaClasses.cpp
587                    (java_lang_Throwable::fill_in_stack_trace). */
588
589                 if (skip_fillInStackTrace == true) {
590                         /* Check "fillInStackTrace" only once, so we negate the
591                            flag after the first time check. */
592
593 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
594                         /* For GNU Classpath we also need to skip
595                            VMThrowable.fillInStackTrace(). */
596
597                         if ((m->clazz == class_java_lang_VMThrowable) &&
598                                 (m->name  == utf_fillInStackTrace))
599                                 continue;
600 #endif
601
602                         skip_fillInStackTrace = false;
603
604                         if (m->name == utf_fillInStackTrace)
605                                 continue;
606                 }
607
608                 /* Skip <init> methods of the exceptions klass.  If there is
609                    <init> methods that belongs to a superclass of the
610                    exception we are going to skipping them in stack trace. */
611
612                 if (skip_init == true) {
613                         if ((m->name == utf_init) &&
614                                 (class_issubclass(m->clazz, class_java_lang_Throwable))) {
615                                 continue;
616                         }
617                         else {
618                                 /* If no "Throwable.init()" method found, we stop
619                                    checking it next time. */
620
621                                 skip_init = false;
622                         }
623                 }
624
625                 /* Store the stacktrace entry and increment the pointer. */
626
627                 ste->code = tmpsfi.code;
628                 ste->pc   = tmpsfi.xpc;
629
630                 ste++;
631         }
632
633         /* Store the number of entries in the stacktrace structure. */
634
635         st->length = ste - st->entries;
636
637         LLNI_CRITICAL_END;
638
639         /* release dump memory */
640
641 /*      dump_release(dumpsize); */
642
643         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
644                                                                    stacktrace_overhead)
645         return ba;
646
647 return_NULL:
648 /*      dump_release(dumpsize); */
649
650         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
651                                                                    stacktrace_overhead)
652
653         return NULL;
654 }
655
656
657 /* stacktrace_get_current ******************************************************
658
659    Builds and returns a stacktrace from the current thread and returns
660    the stacktrace structure wrapped in a Java byte-array to not
661    confuse the GC.
662
663    RETURN:
664        stacktrace as Java byte-array
665
666 *******************************************************************************/
667
668 java_handle_bytearray_t *stacktrace_get_current(void)
669 {
670         stackframeinfo_t        *sfi;
671         java_handle_bytearray_t *ba;
672
673         sfi = threads_get_current_stackframeinfo();
674         ba  = stacktrace_get(sfi);
675
676         return ba;
677 }
678
679
680 /* stacktrace_get_caller_class *************************************************
681
682    Get the class on the stack at the given depth.  This function skips
683    various special classes or methods.
684
685    ARGUMENTS:
686        depth ... depth to get caller class of
687
688    RETURN:
689        caller class
690
691 *******************************************************************************/
692
693 #if defined(ENABLE_JAVASE)
694 classinfo *stacktrace_get_caller_class(int depth)
695 {
696         stackframeinfo_t *sfi;
697         stackframeinfo_t  tmpsfi;
698         methodinfo       *m;
699         classinfo        *c;
700         int               i;
701
702 #if !defined(NDEBUG)
703         if (opt_DebugStackTrace)
704                 log_println("[stacktrace_get_caller_class]");
705 #endif
706
707         /* Get the stackframeinfo of the current thread. */
708
709         sfi = threads_get_current_stackframeinfo();
710
711         /* Iterate over the whole stack until we reached the requested
712            depth. */
713
714         i = 0;
715
716         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
717                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
718                  stacktrace_stackframeinfo_next(&tmpsfi)) {
719
720                 m = tmpsfi.code->m;
721                 c = m->clazz;
722
723                 /* Skip builtin methods. */
724
725                 if (m->flags & ACC_METHOD_BUILTIN)
726                         continue;
727
728 #if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
729                 /* NOTE: See hotspot/src/share/vm/runtime/vframe.cpp
730                    (vframeStreamCommon::security_get_caller_frame). */
731
732                 /* This is java.lang.reflect.Method.invoke(), skip it. */
733
734                 if (m == method_java_lang_reflect_Method_invoke)
735                         continue;
736
737                 /* This is an auxiliary frame, skip it. */
738
739                 if (class_issubclass(c, class_sun_reflect_MagicAccessorImpl))
740                         continue;
741 #endif
742
743                 /* We reached the requested depth. */
744
745                 if (i >= depth)
746                         return c;
747
748                 i++;
749         }
750
751         return NULL;
752 }
753 #endif
754
755
756 /* stacktrace_first_nonnull_classloader ****************************************
757
758    Returns the first non-null (user-defined) classloader on the stack.
759    If none is found NULL is returned.
760
761    RETURN:
762        classloader
763
764 *******************************************************************************/
765
766 classloader_t *stacktrace_first_nonnull_classloader(void)
767 {
768         stackframeinfo_t *sfi;
769         stackframeinfo_t  tmpsfi;
770         methodinfo       *m;
771         classloader_t    *cl;
772
773 #if !defined(NDEBUG)
774         if (opt_DebugStackTrace)
775                 log_println("[stacktrace_first_nonnull_classloader]");
776 #endif
777
778         /* Get the stackframeinfo of the current thread. */
779
780         sfi = threads_get_current_stackframeinfo();
781
782         /* Iterate over the whole stack. */
783
784         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
785                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
786                  stacktrace_stackframeinfo_next(&tmpsfi)) {
787
788                 m  = tmpsfi.code->m;
789                 cl = class_get_classloader(m->clazz);
790
791                 if (cl != NULL)
792                         return cl;
793         }
794
795         return NULL;
796 }
797
798
799 /* stacktrace_getClassContext **************************************************
800
801    Creates a Class context array.
802
803    RETURN VALUE:
804       the array of java.lang.Class objects, or
805           NULL if an exception has been thrown
806
807 *******************************************************************************/
808
809 java_handle_objectarray_t *stacktrace_getClassContext(void)
810 {
811         stackframeinfo_t           *sfi;
812         stackframeinfo_t            tmpsfi;
813         int                         depth;
814         java_handle_objectarray_t  *oa;
815         java_object_t             **data;
816         int                         i;
817         methodinfo                 *m;
818
819         CYCLES_STATS_DECLARE_AND_START
820
821 #if !defined(NDEBUG)
822         if (opt_DebugStackTrace)
823                 log_println("[stacktrace_getClassContext]");
824 #endif
825
826         sfi = threads_get_current_stackframeinfo();
827
828         /* Get the depth of the current stack. */
829
830         depth = stacktrace_depth(sfi);
831
832         /* The first stackframe corresponds to the method whose
833            implementation calls this native function.  We remove that
834            entry. */
835
836         depth--;
837         stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
838         stacktrace_stackframeinfo_next(&tmpsfi);
839
840         /* Allocate the Class array. */
841
842         oa = builtin_anewarray(depth, class_java_lang_Class);
843
844         if (oa == NULL) {
845                 CYCLES_STATS_END(stacktrace_getClassContext);
846
847                 return NULL;
848         }
849
850         /* Fill the Class array from the stacktrace list. */
851
852         LLNI_CRITICAL_START;
853
854         data = LLNI_array_data(oa);
855
856         /* Iterate over the whole stack. */
857
858         i = 0;
859
860         for (;
861                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
862                  stacktrace_stackframeinfo_next(&tmpsfi)) {
863                 /* Get methodinfo. */
864
865                 m = tmpsfi.code->m;
866
867                 /* Skip builtin methods. */
868
869                 if (m->flags & ACC_METHOD_BUILTIN)
870                         continue;
871
872                 /* Store the class in the array. */
873
874                 data[i] = (java_object_t *) m->clazz;
875
876                 i++;
877         }
878
879         LLNI_CRITICAL_END;
880
881         CYCLES_STATS_END(stacktrace_getClassContext)
882
883         return oa;
884 }
885
886
887 /* stacktrace_getCurrentClass **************************************************
888
889    Find the current class by walking the stack trace.
890
891    Quote from the JNI documentation:
892          
893    In the Java 2 Platform, FindClass locates the class loader
894    associated with the current native method.  If the native code
895    belongs to a system class, no class loader will be
896    involved. Otherwise, the proper class loader will be invoked to
897    load and link the named class. When FindClass is called through the
898    Invocation Interface, there is no current native method or its
899    associated class loader. In that case, the result of
900    ClassLoader.getBaseClassLoader is used."
901
902 *******************************************************************************/
903
904 #if defined(ENABLE_JAVASE)
905 classinfo *stacktrace_get_current_class(void)
906 {
907         stackframeinfo_t *sfi;
908         stackframeinfo_t  tmpsfi;
909         methodinfo       *m;
910
911         CYCLES_STATS_DECLARE_AND_START;
912
913 #if !defined(NDEBUG)
914         if (opt_DebugStackTrace)
915                 log_println("[stacktrace_get_current_class]");
916 #endif
917
918         /* Get the stackframeinfo of the current thread. */
919
920         sfi = threads_get_current_stackframeinfo();
921
922         /* If the stackframeinfo is NULL then FindClass is called through
923            the Invocation Interface and we return NULL */
924
925         if (sfi == NULL) {
926                 CYCLES_STATS_END(stacktrace_getCurrentClass);
927
928                 return NULL;
929         }
930
931         /* Iterate over the whole stack. */
932
933         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
934                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
935                  stacktrace_stackframeinfo_next(&tmpsfi)) {
936                 /* Get the methodinfo. */
937
938                 m = tmpsfi.code->m;
939
940                 if (m->clazz == class_java_security_PrivilegedAction) {
941                         CYCLES_STATS_END(stacktrace_getCurrentClass);
942
943                         return NULL;
944                 }
945
946                 if (m->clazz != NULL) {
947                         CYCLES_STATS_END(stacktrace_getCurrentClass);
948
949                         return m->clazz;
950                 }
951         }
952
953         /* No Java method found on the stack. */
954
955         CYCLES_STATS_END(stacktrace_getCurrentClass);
956
957         return NULL;
958 }
959 #endif /* ENABLE_JAVASE */
960
961
962 /* stacktrace_get_stack ********************************************************
963
964    Create a 2-dimensional array for java.security.VMAccessControler.
965
966    RETURN VALUE:
967       the arrary, or
968          NULL if an exception has been thrown
969
970 *******************************************************************************/
971
972 #if defined(ENABLE_JAVASE) && defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
973 java_handle_objectarray_t *stacktrace_get_stack(void)
974 {
975         stackframeinfo_t          *sfi;
976         stackframeinfo_t           tmpsfi;
977         int                        depth;
978         java_handle_objectarray_t *oa;
979         java_handle_objectarray_t *classes;
980         java_handle_objectarray_t *methodnames;
981         methodinfo                *m;
982         java_handle_t             *string;
983         int                        i;
984
985         CYCLES_STATS_DECLARE_AND_START
986
987 #if !defined(NDEBUG)
988         if (opt_DebugStackTrace)
989                 log_println("[stacktrace_get_stack]");
990 #endif
991
992         /* Get the stackframeinfo of the current thread. */
993
994         sfi = threads_get_current_stackframeinfo();
995
996         /* Get the depth of the current stack. */
997
998         depth = stacktrace_depth(sfi);
999
1000         if (depth == 0)
1001                 return NULL;
1002
1003         /* Allocate the required arrays. */
1004
1005         oa = builtin_anewarray(2, arrayclass_java_lang_Object);
1006
1007         if (oa == NULL)
1008                 goto return_NULL;
1009
1010         classes = builtin_anewarray(depth, class_java_lang_Class);
1011
1012         if (classes == NULL)
1013                 goto return_NULL;
1014
1015         methodnames = builtin_anewarray(depth, class_java_lang_String);
1016
1017         if (methodnames == NULL)
1018                 goto return_NULL;
1019
1020         /* Set up the 2-dimensional array. */
1021
1022         array_objectarray_element_set(oa, 0, (java_handle_t *) classes);
1023         array_objectarray_element_set(oa, 1, (java_handle_t *) methodnames);
1024
1025         /* Iterate over the whole stack. */
1026         /* TODO We should use a critical section here to speed things
1027            up. */
1028
1029         i = 0;
1030
1031         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1032                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1033                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1034                 /* Get the methodinfo. */
1035
1036                 m = tmpsfi.code->m;
1037
1038                 /* Skip builtin methods. */
1039
1040                 if (m->flags & ACC_METHOD_BUILTIN)
1041                         continue;
1042
1043                 /* Store the class in the array. */
1044                 /* NOTE: We use a LLNI-macro here, because a classinfo is not
1045                    a handle. */
1046
1047                 LLNI_array_direct(classes, i) = (java_object_t *) m->clazz;
1048
1049                 /* Store the name in the array. */
1050
1051                 string = javastring_new(m->name);
1052
1053                 if (string == NULL)
1054                         goto return_NULL;
1055
1056                 array_objectarray_element_set(methodnames, i, string);
1057
1058                 i++;
1059         }
1060
1061         CYCLES_STATS_END(stacktrace_get_stack)
1062
1063         return oa;
1064
1065 return_NULL:
1066         CYCLES_STATS_END(stacktrace_get_stack)
1067
1068         return NULL;
1069 }
1070 #endif
1071
1072
1073 /* stacktrace_print_entry ****************************************************
1074
1075    Print line for a stacktrace entry.
1076
1077    ARGUMENTS:
1078        m ............ methodinfo of the entry
1079        linenumber ... linenumber of the entry
1080
1081 *******************************************************************************/
1082
1083 static void stacktrace_print_entry(methodinfo *m, int32_t linenumber)
1084 {
1085         /* Sanity check. */
1086
1087         assert(m != NULL);
1088
1089         printf("\tat ");
1090
1091         if (m->flags & ACC_METHOD_BUILTIN)
1092                 printf("NULL");
1093         else
1094                 utf_display_printable_ascii_classname(m->clazz->name);
1095
1096         printf(".");
1097         utf_display_printable_ascii(m->name);
1098         utf_display_printable_ascii(m->descriptor);
1099
1100         if (m->flags & ACC_NATIVE) {
1101                 puts("(Native Method)");
1102         }
1103         else {
1104                 if (m->flags & ACC_METHOD_BUILTIN) {
1105                         puts("(builtin)");
1106                 }
1107                 else {
1108                         printf("(");
1109                         utf_display_printable_ascii(m->clazz->sourcefile);
1110                         printf(":%d)\n", linenumber);
1111                 }
1112         }
1113
1114         fflush(stdout);
1115 }
1116
1117
1118 /* stacktrace_print ************************************************************
1119
1120    Print the given stacktrace with CACAO intern methods only (no Java
1121    code required).
1122
1123    This method is used by stacktrace_dump_trace and
1124    builtin_trace_exception.
1125
1126    IN:
1127        st ... stacktrace to print
1128
1129 *******************************************************************************/
1130
1131 void stacktrace_print(stacktrace_t *st)
1132 {
1133         stacktrace_entry_t *ste;
1134         methodinfo         *m;
1135         int32_t             linenumber;
1136         int                 i;
1137
1138         ste = &(st->entries[0]);
1139
1140         for (i = 0; i < st->length; i++, ste++) {
1141                 m = ste->code->m;
1142
1143                 /* Get the line number. */
1144
1145                 linenumber = linenumbertable_linenumber_for_pc(&m, ste->code, ste->pc);
1146
1147                 stacktrace_print_entry(m, linenumber);
1148         }
1149 }
1150
1151
1152 /* stacktrace_print_current ****************************************************
1153
1154    Print the current stacktrace of the current thread.
1155
1156    NOTE: This function prints all frames of the stacktrace and does
1157    not skip frames like stacktrace_get.
1158
1159 *******************************************************************************/
1160
1161 void stacktrace_print_current(void)
1162 {
1163         stackframeinfo_t *sfi;
1164         stackframeinfo_t  tmpsfi;
1165         codeinfo         *code;
1166         methodinfo       *m;
1167         int32_t           linenumber;
1168
1169         sfi = threads_get_current_stackframeinfo();
1170
1171         if (sfi == NULL) {
1172                 puts("\t<<No stacktrace available>>");
1173                 fflush(stdout);
1174                 return;
1175         }
1176
1177         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1178                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1179                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1180                 /* Get the methodinfo. */
1181
1182                 code = tmpsfi.code;
1183                 m    = code->m;
1184
1185                 /* Get the line number. */
1186
1187                 linenumber = linenumbertable_linenumber_for_pc(&m, code, tmpsfi.xpc);
1188
1189                 stacktrace_print_entry(m, linenumber);
1190         }
1191 }
1192
1193
1194 /* stacktrace_print_of_thread **************************************************
1195
1196    Print the current stacktrace of the given thread.
1197
1198    ARGUMENTS:
1199        t ... thread
1200
1201 *******************************************************************************/
1202
1203 #if defined(ENABLE_THREADS)
1204 void stacktrace_print_of_thread(threadobject *t)
1205 {
1206         stackframeinfo_t *sfi;
1207         stackframeinfo_t  tmpsfi;
1208         codeinfo         *code;
1209         methodinfo       *m;
1210         int32_t           linenumber;
1211
1212         /* Build a stacktrace for the passed thread. */
1213
1214         sfi = t->_stackframeinfo;
1215         
1216         if (sfi == NULL) {
1217                 puts("\t<<No stacktrace available>>");
1218                 fflush(stdout);
1219                 return;
1220         }
1221
1222         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1223                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1224                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1225                 /* Get the methodinfo. */
1226
1227                 code = tmpsfi.code;
1228                 m    = code->m;
1229
1230                 /* Get the line number. */
1231
1232                 linenumber = linenumbertable_linenumber_for_pc(&m, code, tmpsfi.xpc);
1233
1234                 stacktrace_print_entry(m, linenumber);
1235         }
1236 }
1237 #endif
1238
1239
1240 /* stacktrace_print_exception **************************************************
1241
1242    Print the stacktrace of a given exception (more or less a wrapper
1243    to stacktrace_print).
1244
1245    IN:
1246        h ... handle of exception to print
1247
1248 *******************************************************************************/
1249
1250 void stacktrace_print_exception(java_handle_t *h)
1251 {
1252         if (h == NULL)
1253                 return;
1254
1255         java_lang_Throwable t(h);
1256
1257         /* now print the stacktrace */
1258
1259 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
1260
1261         java_lang_VMThrowable vmt(t.get_vmState());
1262         java_handle_bytearray_t* backtrace = vmt.get_vmdata();
1263
1264 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) || defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
1265
1266         LLNI_field_get_ref(o, backtrace, backtrace);
1267
1268 #else
1269 # error unknown classpath configuration
1270 #endif
1271
1272         // Sanity check.
1273
1274         assert(backtrace != NULL);
1275
1276         /* We need a critical section here as we use the byte-array data
1277            pointer directly. */
1278
1279         LLNI_CRITICAL_START;
1280         
1281         stacktrace_t* st = (stacktrace_t*) LLNI_array_data(backtrace);
1282
1283         stacktrace_print(st);
1284
1285         LLNI_CRITICAL_END;
1286 }
1287
1288
1289 #if defined(ENABLE_CYCLES_STATS)
1290 void stacktrace_print_cycles_stats(FILE *file)
1291 {
1292         CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead, file);
1293         CYCLES_STATS_PRINT(stacktrace_get,               file);
1294         CYCLES_STATS_PRINT(stacktrace_getClassContext ,  file);
1295         CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,  file);
1296         CYCLES_STATS_PRINT(stacktrace_get_stack,         file);
1297 }
1298 #endif
1299
1300 } // extern "C"
1301
1302
1303 /*
1304  * These are local overrides for various environment variables in Emacs.
1305  * Please do not remove this and leave it at the end of the file, where
1306  * Emacs will automagically detect them.
1307  * ---------------------------------------------------------------------
1308  * Local variables:
1309  * mode: c++
1310  * indent-tabs-mode: t
1311  * c-basic-offset: 4
1312  * tab-width: 4
1313  * End:
1314  * vim:noexpandtab:sw=4:ts=4:
1315  */