* src/threads/threadlist.hpp (ThreadList::get_active_threads): Added.
[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.hpp"
39
40 #include "vm/jit/stacktrace.hpp"
41
42 #include "native/llni.h"
43
44 #include "threads/thread.hpp"
45
46 #include "toolbox/logging.hpp"
47
48 #include "vm/array.hpp"
49 #include "vm/jit/builtin.hpp"
50 #include "vm/class.hpp"
51 #include "vm/cycles-stats.h"
52 #include "vm/exceptions.hpp"
53 #include "vm/globals.hpp"
54 #include "vm/javaobjects.hpp"
55 #include "vm/loader.hpp"
56 #include "vm/method.hpp"
57 #include "vm/options.h"
58 #include "vm/string.hpp"
59 #include "vm/vm.hpp"
60
61 #include "vm/jit/asmpart.h"
62 #include "vm/jit/codegen-common.hpp"
63 #include "vm/jit/linenumbertable.hpp"
64 #include "vm/jit/methodheader.h"
65 #include "vm/jit/methodtree.h"
66
67
68 // FIXME Use C-linkage for now.
69 extern "C" {
70
71 /* global variables ***********************************************************/
72
73 CYCLES_STATS_DECLARE(stacktrace_overhead        , 100, 1)
74 CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace, 40,  5000)
75 CYCLES_STATS_DECLARE(stacktrace_get,              40,  5000)
76 CYCLES_STATS_DECLARE(stacktrace_getClassContext , 40,  5000)
77 CYCLES_STATS_DECLARE(stacktrace_getCurrentClass , 40,  5000)
78 CYCLES_STATS_DECLARE(stacktrace_get_stack       , 40,  10000)
79
80
81 /* stacktrace_stackframeinfo_add ***********************************************
82
83    Fills a stackframe info structure with the given or calculated
84    values and adds it to the chain.
85
86 *******************************************************************************/
87
88 void stacktrace_stackframeinfo_add(stackframeinfo_t* sfi, void* pv, void* sp, void* ra, void* xpc)
89 {
90         stackframeinfo_t *currentsfi;
91         codeinfo         *code;
92 #if defined(ENABLE_JIT)
93         s4                 framesize;
94 #endif
95
96         /* Get current stackframe info. */
97
98         currentsfi = threads_get_current_stackframeinfo();
99
100         /* sometimes we don't have pv handy (e.g. in asmpart.S:
101        L_asm_call_jit_compiler_exception or in the interpreter). */
102
103         if (pv == NULL) {
104 #if defined(ENABLE_INTRP)
105                 if (opt_intrp)
106                         pv = methodtree_find(ra);
107                 else
108 #endif
109                         {
110 #if defined(ENABLE_JIT)
111 # if defined(__SPARC_64__)
112                                 pv = md_get_pv_from_stackframe(sp);
113 # else
114                                 pv = md_codegen_get_pv_from_pc(ra);
115 # endif
116 #endif
117                         }
118         }
119
120         /* Get codeinfo pointer for the parent Java method. */
121
122         code = code_get_codeinfo_for_pv(pv);
123
124         /* XXX */
125         /*      assert(m != NULL); */
126
127 #if defined(ENABLE_JIT)
128 # if defined(ENABLE_INTRP)
129         /* When using the interpreter, we pass RA to the function. */
130
131         if (!opt_intrp) {
132 # endif
133 # if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__M68K__)
134                 /* On i386 and x86_64 we always have to get the return address
135                    from the stack. */
136                 /* m68k has return address on stack always */
137                 /* On S390 we use REG_RA as REG_ITMP3, so we have always to get
138                    the RA from stack. */
139
140                 framesize = *((u4 *) (((uintptr_t) pv) + FrameSize));
141
142                 ra = md_stacktrace_get_returnaddress(sp, framesize);
143 # else
144                 /* If the method is a non-leaf function, we need to get the
145                    return address from the stack.  For leaf functions the
146                    return address is set correctly.  This makes the assembler
147                    and the signal handler code simpler.  The code is NULL is
148                    the asm_vm_call_method special case. */
149
150                 if ((code == NULL) || !code_is_leafmethod(code)) {
151                         framesize = *((u4 *) (((uintptr_t) pv) + FrameSize));
152
153                         ra = md_stacktrace_get_returnaddress(sp, framesize);
154                 }
155 # endif
156 # if defined(ENABLE_INTRP)
157         }
158 # endif
159 #endif
160
161         /* Calculate XPC when not given.  The XPC is then the return
162            address of the current method minus 1 because the RA points to
163            the instruction after the call instruction.  This is required
164            e.g. for method stubs. */
165
166         if (xpc == NULL) {
167                 xpc = (void *) (((intptr_t) ra) - 1);
168         }
169
170         /* Fill new stackframeinfo structure. */
171
172         sfi->prev = currentsfi;
173         sfi->code = code;
174         sfi->pv   = pv;
175         sfi->sp   = sp;
176         sfi->ra   = ra;
177         sfi->xpc  = xpc;
178
179 #if !defined(NDEBUG)
180         if (opt_DebugStackFrameInfo) {
181                 log_start();
182                 log_print("[stackframeinfo add   : sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
183                                   sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
184                 method_print(sfi->code->m);
185                 log_print("]");
186                 log_finish();
187         }
188 #endif
189
190         /* Store new stackframeinfo pointer. */
191
192         threads_set_current_stackframeinfo(sfi);
193
194         /* set the native world flag for the current thread */
195         /* ATTENTION: This flag tells the GC how to treat this thread in case of
196            a collection. Set this flag _after_ a valid stackframe info was set. */
197
198         THREAD_NATIVEWORLD_ENTER;
199 }
200
201
202 /* stacktrace_stackframeinfo_remove ********************************************
203
204    Remove the given stackframeinfo from the chain in the current
205    thread.
206
207 *******************************************************************************/
208
209 void stacktrace_stackframeinfo_remove(stackframeinfo_t *sfi)
210 {
211         /* Clear the native world flag for the current thread. */
212         /* ATTENTION: Clear this flag _before_ removing the stackframe info. */
213
214         THREAD_NATIVEWORLD_EXIT;
215
216 #if !defined(NDEBUG)
217         if (opt_DebugStackFrameInfo) {
218                 log_start();
219                 log_print("[stackframeinfo remove: sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
220                                   sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
221                 method_print(sfi->code->m);
222                 log_print("]");
223                 log_finish();
224         }
225 #endif
226
227         /* Set previous stackframe info. */
228
229         threads_set_current_stackframeinfo(sfi->prev);
230 }
231
232
233 /* stacktrace_stackframeinfo_fill **********************************************
234
235    Fill the temporary stackframeinfo structure with the values given
236    in sfi.
237
238    IN:
239        tmpsfi ... temporary stackframeinfo
240        sfi ...... stackframeinfo to be used in the next iteration
241
242 *******************************************************************************/
243
244 static inline void stacktrace_stackframeinfo_fill(stackframeinfo_t *tmpsfi, stackframeinfo_t *sfi)
245 {
246         /* Sanity checks. */
247
248         assert(tmpsfi != NULL);
249         assert(sfi != NULL);
250
251         /* Fill the temporary stackframeinfo. */
252
253         tmpsfi->code = sfi->code;
254         tmpsfi->pv   = sfi->pv;
255         tmpsfi->sp   = sfi->sp;
256         tmpsfi->ra   = sfi->ra;
257         tmpsfi->xpc  = sfi->xpc;
258
259         /* Set the previous stackframe info of the temporary one to the
260            next in the chain. */
261
262         tmpsfi->prev = sfi->prev;
263
264 #if !defined(NDEBUG)
265         if (opt_DebugStackTrace)
266                 log_println("[stacktrace fill]");
267 #endif
268 }
269
270
271 /* stacktrace_stackframeinfo_next **********************************************
272
273    Walk the stack (or the stackframeinfo-chain) to the next method and
274    return the new stackframe values in the temporary stackframeinfo
275    passed.
276
277    ATTENTION: This function does NOT skip builtin methods!
278
279    IN:
280        tmpsfi ... temporary stackframeinfo of current method
281
282 *******************************************************************************/
283
284 static inline void stacktrace_stackframeinfo_next(stackframeinfo_t *tmpsfi)
285 {
286         codeinfo         *code;
287         void             *pv;
288         void             *sp;
289         void             *ra;
290         void             *xpc;
291         uint32_t          framesize;
292         stackframeinfo_t *prevsfi;
293
294         /* Sanity check. */
295
296         assert(tmpsfi != NULL);
297
298         /* Get values from the stackframeinfo. */
299
300         code = tmpsfi->code;
301         pv   = tmpsfi->pv;
302         sp   = tmpsfi->sp;
303         ra   = tmpsfi->ra;
304         xpc  = tmpsfi->xpc;
305  
306         /* Get the current stack frame size. */
307
308         framesize = *((uint32_t *) (((intptr_t) pv) + FrameSize));
309
310         /* Get the RA of the current stack frame (RA to the parent Java
311            method) if the current method is a non-leaf method.  Otherwise
312            the value in the stackframeinfo is correct (from the signal
313            handler). */
314
315 #if defined(ENABLE_JIT)
316 # if defined(ENABLE_INTRP)
317         if (opt_intrp)
318                 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
319         else
320 # endif
321                 {
322                         if (!code_is_leafmethod(code))
323                                 ra = md_stacktrace_get_returnaddress(sp, framesize);
324                 }
325 #else
326         ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
327 #endif
328
329         /* Get the PV for the parent Java method. */
330
331 #if defined(ENABLE_INTRP)
332         if (opt_intrp)
333                 pv = methodtree_find(ra);
334         else
335 #endif
336                 {
337 #if defined(ENABLE_JIT)
338 # if defined(__SPARC_64__)
339                         sp = md_get_framepointer(sp);
340                         pv = md_get_pv_from_stackframe(sp);
341 # else
342                         pv = md_codegen_get_pv_from_pc(ra);
343 # endif
344 #endif
345                 }
346
347         /* Get the codeinfo pointer for the parent Java method. */
348
349         code = code_get_codeinfo_for_pv(pv);
350
351         /* Calculate the SP for the parent Java method. */
352
353 #if defined(ENABLE_INTRP)
354         if (opt_intrp)
355                 sp = *(u1 **) (sp - framesize);
356         else
357 #endif
358                 {
359 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
360                         sp = (void *) (((intptr_t) sp) + framesize + SIZEOF_VOID_P);
361 #elif defined(__SPARC_64__)
362                         /* already has the new sp */
363 #else
364                         sp = (void *) (((intptr_t) sp) + framesize);
365 #endif
366                 }
367
368         /* If the new codeinfo pointer is NULL we reached a
369            asm_vm_call_method function.  In this case we get the next
370            values from the previous stackframeinfo in the chain.
371            Otherwise the new values have been calculated before. */
372
373         if (code == NULL) {
374                 prevsfi = tmpsfi->prev;
375
376                 /* If the previous stackframeinfo in the chain is NULL we
377                    reached the top of the stacktrace.  We set code and prev to
378                    NULL to mark the end, which is checked in
379                    stacktrace_stackframeinfo_end_check. */
380
381                 if (prevsfi == NULL) {
382                         tmpsfi->code = NULL;
383                         tmpsfi->prev = NULL;
384                         return;
385                 }
386
387                 /* Fill the temporary stackframeinfo with the new values. */
388
389                 stacktrace_stackframeinfo_fill(tmpsfi, prevsfi);
390         }
391         else {
392                 /* Store the new values in the stackframeinfo.  NOTE: We
393                    subtract 1 from the RA to get the XPC, because the RA
394                    points to the instruction after the call instruction. */
395
396                 tmpsfi->code = code;
397                 tmpsfi->pv   = pv;
398                 tmpsfi->sp   = sp;
399                 tmpsfi->ra   = ra;
400                 tmpsfi->xpc  = (void *) (((intptr_t) ra) - 1);
401         }
402
403 #if !defined(NDEBUG)
404         /* Print current method information. */
405
406         if (opt_DebugStackTrace) {
407                 log_start();
408                 log_print("[stacktrace: method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
409                                   tmpsfi->code->m, tmpsfi->pv, tmpsfi->sp, tmpsfi->ra,
410                                   tmpsfi->xpc);
411                 method_print(tmpsfi->code->m);
412                 log_print("]");
413                 log_finish();
414         }
415 #endif
416 }
417
418
419 /* stacktrace_stackframeinfo_end_check *****************************************
420
421    Check if we reached the end of the stacktrace.
422
423    IN:
424        tmpsfi ... temporary stackframeinfo of current method
425
426    RETURN:
427        true .... the end is reached
428            false ... the end is not reached
429
430 *******************************************************************************/
431
432 static inline bool stacktrace_stackframeinfo_end_check(stackframeinfo_t *tmpsfi)
433 {
434         /* Sanity check. */
435
436         assert(tmpsfi != NULL);
437
438         if ((tmpsfi->code == NULL) && (tmpsfi->prev == NULL)) {
439 #if !defined(NDEBUG)
440                 if (opt_DebugStackTrace)
441                         log_println("[stacktrace stop]");
442 #endif
443
444                 return true;
445         }
446
447         return false;
448 }
449
450
451 /* stacktrace_depth ************************************************************
452
453    Calculates and returns the depth of the current stacktrace.
454
455    IN:
456        sfi ... stackframeinfo where to start the stacktrace
457
458    RETURN:
459        depth of the stacktrace
460
461 *******************************************************************************/
462
463 static int stacktrace_depth(stackframeinfo_t *sfi)
464 {
465         stackframeinfo_t  tmpsfi;
466         int               depth;
467         methodinfo       *m;
468
469 #if !defined(NDEBUG)
470         if (opt_DebugStackTrace)
471                 log_println("[stacktrace_depth]");
472 #endif
473
474         /* XXX This is not correct, but a workaround for threads-dump for
475            now. */
476 /*      assert(sfi != NULL); */
477         if (sfi == NULL)
478                 return 0;
479
480         /* Iterate over all stackframes. */
481
482         depth = 0;
483
484         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
485                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
486                  stacktrace_stackframeinfo_next(&tmpsfi)) {
487                 /* Get methodinfo. */
488
489                 m = tmpsfi.code->m;
490
491                 /* Skip builtin methods. */
492
493                 if (m->flags & ACC_METHOD_BUILTIN)
494                         continue;
495
496                 depth++;
497         }
498
499         return depth;
500 }
501
502
503 /* stacktrace_get **************************************************************
504
505    Builds and returns a stacktrace starting from the given stackframe
506    info and returns the stacktrace structure wrapped in a Java
507    byte-array to not confuse the GC.
508
509    IN:
510        sfi ... stackframe info to start stacktrace from
511
512    RETURN:
513        stacktrace as Java byte-array
514
515 *******************************************************************************/
516
517 java_handle_bytearray_t *stacktrace_get(stackframeinfo_t *sfi)
518 {
519         stackframeinfo_t         tmpsfi;
520         int                      depth;
521         java_handle_bytearray_t *ba;
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         ba = builtin_newarray_byte(ba_size);
554
555         if (ba == 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 *) LLNI_array_data(ba);
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;
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         java_handle_objectarray_t* oa = builtin_anewarray(length, class_java_lang_StackTraceElement);
778
779         if (oa == 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                 array_objectarray_element_set(oa, i, h);
793         }
794
795         return oa;
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 /* stacktrace_first_nonnull_classloader ****************************************
877
878    Returns the first non-null (user-defined) classloader on the stack.
879    If none is found NULL is returned.
880
881    RETURN:
882        classloader
883
884 *******************************************************************************/
885
886 classloader_t *stacktrace_first_nonnull_classloader(void)
887 {
888         stackframeinfo_t *sfi;
889         stackframeinfo_t  tmpsfi;
890         methodinfo       *m;
891         classloader_t    *cl;
892
893 #if !defined(NDEBUG)
894         if (opt_DebugStackTrace)
895                 log_println("[stacktrace_first_nonnull_classloader]");
896 #endif
897
898         /* Get the stackframeinfo of the current thread. */
899
900         sfi = threads_get_current_stackframeinfo();
901
902         /* Iterate over the whole stack. */
903
904         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
905                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
906                  stacktrace_stackframeinfo_next(&tmpsfi)) {
907
908                 m  = tmpsfi.code->m;
909                 cl = class_get_classloader(m->clazz);
910
911                 if (cl != NULL)
912                         return cl;
913         }
914
915         return NULL;
916 }
917
918
919 /* stacktrace_getClassContext **************************************************
920
921    Creates a Class context array.
922
923    RETURN VALUE:
924       the array of java.lang.Class objects, or
925           NULL if an exception has been thrown
926
927 *******************************************************************************/
928
929 java_handle_objectarray_t *stacktrace_getClassContext(void)
930 {
931         stackframeinfo_t           *sfi;
932         stackframeinfo_t            tmpsfi;
933         int                         depth;
934         java_handle_objectarray_t  *oa;
935         java_object_t             **data;
936         int                         i;
937         methodinfo                 *m;
938
939         CYCLES_STATS_DECLARE_AND_START
940
941 #if !defined(NDEBUG)
942         if (opt_DebugStackTrace)
943                 log_println("[stacktrace_getClassContext]");
944 #endif
945
946         sfi = threads_get_current_stackframeinfo();
947
948         /* Get the depth of the current stack. */
949
950         depth = stacktrace_depth(sfi);
951
952         /* The first stackframe corresponds to the method whose
953            implementation calls this native function.  We remove that
954            entry. */
955
956         depth--;
957         stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
958         stacktrace_stackframeinfo_next(&tmpsfi);
959
960         /* Allocate the Class array. */
961
962         oa = builtin_anewarray(depth, class_java_lang_Class);
963
964         if (oa == NULL) {
965                 CYCLES_STATS_END(stacktrace_getClassContext);
966
967                 return NULL;
968         }
969
970         /* Fill the Class array from the stacktrace list. */
971
972         LLNI_CRITICAL_START;
973
974         data = LLNI_array_data(oa);
975
976         /* Iterate over the whole stack. */
977
978         i = 0;
979
980         for (;
981                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
982                  stacktrace_stackframeinfo_next(&tmpsfi)) {
983                 /* Get methodinfo. */
984
985                 m = tmpsfi.code->m;
986
987                 /* Skip builtin methods. */
988
989                 if (m->flags & ACC_METHOD_BUILTIN)
990                         continue;
991
992                 /* Store the class in the array. */
993
994                 data[i] = (java_object_t *) m->clazz;
995
996                 i++;
997         }
998
999         LLNI_CRITICAL_END;
1000
1001         CYCLES_STATS_END(stacktrace_getClassContext)
1002
1003         return oa;
1004 }
1005
1006
1007 /* stacktrace_getCurrentClass **************************************************
1008
1009    Find the current class by walking the stack trace.
1010
1011    Quote from the JNI documentation:
1012          
1013    In the Java 2 Platform, FindClass locates the class loader
1014    associated with the current native method.  If the native code
1015    belongs to a system class, no class loader will be
1016    involved. Otherwise, the proper class loader will be invoked to
1017    load and link the named class. When FindClass is called through the
1018    Invocation Interface, there is no current native method or its
1019    associated class loader. In that case, the result of
1020    ClassLoader.getBaseClassLoader is used."
1021
1022 *******************************************************************************/
1023
1024 #if defined(ENABLE_JAVASE)
1025 classinfo *stacktrace_get_current_class(void)
1026 {
1027         stackframeinfo_t *sfi;
1028         stackframeinfo_t  tmpsfi;
1029         methodinfo       *m;
1030
1031         CYCLES_STATS_DECLARE_AND_START;
1032
1033 #if !defined(NDEBUG)
1034         if (opt_DebugStackTrace)
1035                 log_println("[stacktrace_get_current_class]");
1036 #endif
1037
1038         /* Get the stackframeinfo of the current thread. */
1039
1040         sfi = threads_get_current_stackframeinfo();
1041
1042         /* If the stackframeinfo is NULL then FindClass is called through
1043            the Invocation Interface and we return NULL */
1044
1045         if (sfi == NULL) {
1046                 CYCLES_STATS_END(stacktrace_getCurrentClass);
1047
1048                 return NULL;
1049         }
1050
1051         /* Iterate over the whole stack. */
1052
1053         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1054                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1055                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1056                 /* Get the methodinfo. */
1057
1058                 m = tmpsfi.code->m;
1059
1060                 if (m->clazz == class_java_security_PrivilegedAction) {
1061                         CYCLES_STATS_END(stacktrace_getCurrentClass);
1062
1063                         return NULL;
1064                 }
1065
1066                 if (m->clazz != NULL) {
1067                         CYCLES_STATS_END(stacktrace_getCurrentClass);
1068
1069                         return m->clazz;
1070                 }
1071         }
1072
1073         /* No Java method found on the stack. */
1074
1075         CYCLES_STATS_END(stacktrace_getCurrentClass);
1076
1077         return NULL;
1078 }
1079 #endif /* ENABLE_JAVASE */
1080
1081
1082 /* stacktrace_get_stack ********************************************************
1083
1084    Create a 2-dimensional array for java.security.VMAccessControler.
1085
1086    RETURN VALUE:
1087       the arrary, or
1088          NULL if an exception has been thrown
1089
1090 *******************************************************************************/
1091
1092 #if defined(ENABLE_JAVASE) && defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
1093 java_handle_objectarray_t *stacktrace_get_stack(void)
1094 {
1095         stackframeinfo_t          *sfi;
1096         stackframeinfo_t           tmpsfi;
1097         int                        depth;
1098         java_handle_objectarray_t *oa;
1099         java_handle_objectarray_t *classes;
1100         java_handle_objectarray_t *methodnames;
1101         methodinfo                *m;
1102         java_handle_t             *string;
1103         int                        i;
1104
1105         CYCLES_STATS_DECLARE_AND_START
1106
1107 #if !defined(NDEBUG)
1108         if (opt_DebugStackTrace)
1109                 log_println("[stacktrace_get_stack]");
1110 #endif
1111
1112         /* Get the stackframeinfo of the current thread. */
1113
1114         sfi = threads_get_current_stackframeinfo();
1115
1116         /* Get the depth of the current stack. */
1117
1118         depth = stacktrace_depth(sfi);
1119
1120         if (depth == 0)
1121                 return NULL;
1122
1123         /* Allocate the required arrays. */
1124
1125         oa = builtin_anewarray(2, arrayclass_java_lang_Object);
1126
1127         if (oa == NULL)
1128                 goto return_NULL;
1129
1130         classes = builtin_anewarray(depth, class_java_lang_Class);
1131
1132         if (classes == NULL)
1133                 goto return_NULL;
1134
1135         methodnames = builtin_anewarray(depth, class_java_lang_String);
1136
1137         if (methodnames == NULL)
1138                 goto return_NULL;
1139
1140         /* Set up the 2-dimensional array. */
1141
1142         array_objectarray_element_set(oa, 0, (java_handle_t *) classes);
1143         array_objectarray_element_set(oa, 1, (java_handle_t *) methodnames);
1144
1145         /* Iterate over the whole stack. */
1146         /* TODO We should use a critical section here to speed things
1147            up. */
1148
1149         i = 0;
1150
1151         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1152                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1153                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1154                 /* Get the methodinfo. */
1155
1156                 m = tmpsfi.code->m;
1157
1158                 /* Skip builtin methods. */
1159
1160                 if (m->flags & ACC_METHOD_BUILTIN)
1161                         continue;
1162
1163                 /* Store the class in the array. */
1164                 /* NOTE: We use a LLNI-macro here, because a classinfo is not
1165                    a handle. */
1166
1167                 LLNI_array_direct(classes, i) = (java_object_t *) m->clazz;
1168
1169                 /* Store the name in the array. */
1170
1171                 string = javastring_new(m->name);
1172
1173                 if (string == NULL)
1174                         goto return_NULL;
1175
1176                 array_objectarray_element_set(methodnames, i, string);
1177
1178                 i++;
1179         }
1180
1181         CYCLES_STATS_END(stacktrace_get_stack)
1182
1183         return oa;
1184
1185 return_NULL:
1186         CYCLES_STATS_END(stacktrace_get_stack)
1187
1188         return NULL;
1189 }
1190 #endif
1191
1192
1193 /* stacktrace_print_entry ****************************************************
1194
1195    Print line for a stacktrace entry.
1196
1197    ARGUMENTS:
1198        m ............ methodinfo of the entry
1199        linenumber ... linenumber of the entry
1200
1201 *******************************************************************************/
1202
1203 static void stacktrace_print_entry(methodinfo *m, int32_t linenumber)
1204 {
1205         /* Sanity check. */
1206
1207         assert(m != NULL);
1208
1209         printf("\tat ");
1210
1211         if (m->flags & ACC_METHOD_BUILTIN)
1212                 printf("NULL");
1213         else
1214                 utf_display_printable_ascii_classname(m->clazz->name);
1215
1216         printf(".");
1217         utf_display_printable_ascii(m->name);
1218         utf_display_printable_ascii(m->descriptor);
1219
1220         if (m->flags & ACC_NATIVE) {
1221                 puts("(Native Method)");
1222         }
1223         else {
1224                 if (m->flags & ACC_METHOD_BUILTIN) {
1225                         puts("(builtin)");
1226                 }
1227                 else {
1228                         printf("(");
1229                         utf_display_printable_ascii(m->clazz->sourcefile);
1230                         printf(":%d)\n", linenumber);
1231                 }
1232         }
1233
1234         fflush(stdout);
1235 }
1236
1237
1238 /* stacktrace_print ************************************************************
1239
1240    Print the given stacktrace with CACAO intern methods only (no Java
1241    code required).
1242
1243    This method is used by stacktrace_dump_trace and
1244    builtin_trace_exception.
1245
1246    IN:
1247        st ... stacktrace to print
1248
1249 *******************************************************************************/
1250
1251 void stacktrace_print(stacktrace_t *st)
1252 {
1253         stacktrace_entry_t *ste;
1254         methodinfo         *m;
1255         int32_t             linenumber;
1256         int                 i;
1257
1258         ste = &(st->entries[0]);
1259
1260         for (i = 0; i < st->length; i++, ste++) {
1261                 m = ste->code->m;
1262
1263                 /* Get the line number. */
1264
1265                 linenumber = ste->code->linenumbertable->find(&m, ste->pc);
1266
1267                 stacktrace_print_entry(m, linenumber);
1268         }
1269 }
1270
1271
1272 /* stacktrace_print_current ****************************************************
1273
1274    Print the current stacktrace of the current thread.
1275
1276    NOTE: This function prints all frames of the stacktrace and does
1277    not skip frames like stacktrace_get.
1278
1279 *******************************************************************************/
1280
1281 void stacktrace_print_current(void)
1282 {
1283         stackframeinfo_t *sfi;
1284         stackframeinfo_t  tmpsfi;
1285         codeinfo         *code;
1286         methodinfo       *m;
1287         int32_t           linenumber;
1288
1289         sfi = threads_get_current_stackframeinfo();
1290
1291         if (sfi == NULL) {
1292                 puts("\t<<No stacktrace available>>");
1293                 fflush(stdout);
1294                 return;
1295         }
1296
1297         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1298                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1299                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1300                 /* Get the methodinfo. */
1301
1302                 code = tmpsfi.code;
1303                 m    = code->m;
1304
1305                 // Get the line number.
1306                 linenumber = code->linenumbertable->find(&m, tmpsfi.xpc);
1307
1308                 stacktrace_print_entry(m, linenumber);
1309         }
1310 }
1311
1312
1313 /**
1314  * Creates a stacktrace for the given thread.
1315  *
1316  * @param t Given thread.
1317  * @return Current stacktrace of the given thread.
1318  *
1319  * XXX: Creation of the stacktrace starts at the most recent
1320  * stackframeinfo block. If the thread is not inside the native
1321  * world, the created stacktrace is not complete!
1322  */
1323 #if defined(ENABLE_THREADS)
1324 stacktrace_t* stacktrace_get_of_thread(threadobject* t)
1325 {
1326         stackframeinfo_t*        sfi;
1327         java_handle_bytearray_t* ba;
1328         stacktrace_t*            st;
1329
1330         sfi = t->_stackframeinfo;
1331         ba  = stacktrace_get(sfi);
1332
1333         if (ba == NULL)
1334                 return NULL;
1335
1336         st  = (stacktrace_t*) LLNI_array_data(ba);
1337
1338         return st;
1339 }
1340 #endif
1341
1342
1343 /* stacktrace_print_of_thread **************************************************
1344
1345    Print the current stacktrace of the given thread.
1346
1347    ARGUMENTS:
1348        t ... thread
1349
1350 *******************************************************************************/
1351
1352 #if defined(ENABLE_THREADS)
1353 void stacktrace_print_of_thread(threadobject *t)
1354 {
1355         stackframeinfo_t *sfi;
1356         stackframeinfo_t  tmpsfi;
1357         codeinfo         *code;
1358         methodinfo       *m;
1359         int32_t           linenumber;
1360
1361         /* Build a stacktrace for the passed thread. */
1362
1363         sfi = t->_stackframeinfo;
1364         
1365         if (sfi == NULL) {
1366                 puts("\t<<No stacktrace available>>");
1367                 fflush(stdout);
1368                 return;
1369         }
1370
1371         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1372                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1373                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1374                 /* Get the methodinfo. */
1375
1376                 code = tmpsfi.code;
1377                 m    = code->m;
1378
1379                 // Get the line number.
1380                 linenumber = code->linenumbertable->find(&m, tmpsfi.xpc);
1381
1382                 stacktrace_print_entry(m, linenumber);
1383         }
1384 }
1385 #endif
1386
1387
1388 /* stacktrace_print_exception **************************************************
1389
1390    Print the stacktrace of a given exception (more or less a wrapper
1391    to stacktrace_print).
1392
1393    IN:
1394        h ... handle of exception to print
1395
1396 *******************************************************************************/
1397
1398 void stacktrace_print_exception(java_handle_t *h)
1399 {
1400         if (h == NULL)
1401                 return;
1402
1403         java_lang_Throwable t(h);
1404
1405         /* now print the stacktrace */
1406
1407 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
1408
1409         java_lang_VMThrowable vmt(t.get_vmState());
1410         java_handle_bytearray_t* backtrace = vmt.get_vmdata();
1411
1412 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) || defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
1413
1414         java_handle_bytearray_t* backtrace = t.get_backtrace();
1415
1416 #else
1417 # error unknown classpath configuration
1418 #endif
1419
1420         // Sanity check.
1421
1422         assert(backtrace != NULL);
1423
1424         /* We need a critical section here as we use the byte-array data
1425            pointer directly. */
1426
1427         LLNI_CRITICAL_START;
1428         
1429         stacktrace_t* st = (stacktrace_t*) LLNI_array_data(backtrace);
1430
1431         stacktrace_print(st);
1432
1433         LLNI_CRITICAL_END;
1434 }
1435
1436
1437 #if defined(ENABLE_CYCLES_STATS)
1438 void stacktrace_print_cycles_stats(FILE *file)
1439 {
1440         CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead, file);
1441         CYCLES_STATS_PRINT(stacktrace_get,               file);
1442         CYCLES_STATS_PRINT(stacktrace_getClassContext ,  file);
1443         CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,  file);
1444         CYCLES_STATS_PRINT(stacktrace_get_stack,         file);
1445 }
1446 #endif
1447
1448 } // extern "C"
1449
1450
1451 /*
1452  * These are local overrides for various environment variables in Emacs.
1453  * Please do not remove this and leave it at the end of the file, where
1454  * Emacs will automagically detect them.
1455  * ---------------------------------------------------------------------
1456  * Local variables:
1457  * mode: c++
1458  * indent-tabs-mode: t
1459  * c-basic-offset: 4
1460  * tab-width: 4
1461  * End:
1462  * vim:noexpandtab:sw=4:ts=4:
1463  */