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