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