* src/vm/jit/stacktrace.cpp
[cacao.git] / src / vm / jit / stacktrace.cpp
1 /* src/vm/jit/stacktrace.cpp - machine independent stacktrace system
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <assert.h>
29 #include <stdint.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "vm/types.h"
34
35 #include "md.h"
36
37 #include "mm/gc.hpp"
38 #include "mm/memory.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         if ((index < 0) || (index >= st->length)) {
689                 /* XXX This should be an IndexOutOfBoundsException (check this
690                    again). */
691                 exceptions_throw_arrayindexoutofboundsexception();
692                 return NULL;
693         }
694
695         // Get the stacktrace entry.
696         stacktrace_entry_t* ste = &(st->entries[index]);
697
698         // Get the codeinfo, methodinfo and classinfo.
699         codeinfo*   code = ste->code;
700         methodinfo* m    = code->m;
701         classinfo*  c    = m->clazz;
702
703         // Get filename.
704         java_handle_t* filename;
705
706         if (!(m->flags & ACC_NATIVE)) {
707                 if (c->sourcefile != NULL)
708                         filename = javastring_new(c->sourcefile);
709                 else
710                         filename = NULL;
711         }
712         else
713                 filename = NULL;
714
715         // Get line number.
716         int32_t linenumber;
717
718         if (m->flags & ACC_NATIVE) {
719 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
720                 linenumber = -1;
721 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
722                 linenumber = -2;
723 #else
724 # error unknown classpath configuration
725 #endif
726         }
727         else {
728                 // FIXME linenumbertable->find could change the methodinfo
729                 // pointer when hitting an inlined method.
730                 linenumber = code->linenumbertable->find(&m, ste->pc);
731                 linenumber = (linenumber == 0) ? -1 : linenumber;
732         }
733
734         // Get declaring class name.
735         java_handle_t* declaringclass = class_get_classname(c);
736
737 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
738         // Allocate a new StackTraceElement object.
739         java_handle_t* h = builtin_new(class_java_lang_StackTraceElement);
740
741         if (h == NULL)
742                         return NULL;
743
744         java_lang_StackTraceElement jlste(h, filename, linenumber, declaringclass, javastring_new(m->name), ((m->flags & ACC_NATIVE) ? 1 : 0));
745 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
746         // Allocate a new StackTraceElement object.
747         java_lang_StackTraceElement jlste(declaringclass, javastring_new(m->name), filename, linenumber);
748
749         if (jlste.is_null())
750                 return NULL;
751 #else
752 # error unknown classpath configuration
753 #endif
754
755         return jlste.get_handle();
756 }
757 #endif
758
759
760 /**
761  * Creates a complete array of java.lang.StackTraceElement objects
762  * for the given stacktrace.
763  *
764  * @param st Given stacktrace.
765  * @return Array of filled StackTraceElement objects.
766  */
767 #if defined(ENABLE_JAVASE)
768 java_handle_objectarray_t* stacktrace_get_StackTraceElements(stacktrace_t* st)
769 {
770         // Create the stacktrace element array.
771         java_handle_objectarray_t* oa = builtin_anewarray(st->length, class_java_lang_StackTraceElement);
772
773         if (oa == NULL)
774                 return NULL;
775
776         // Iterate over all stacktrace elements.
777         for (int i = 0; i < st->length; i++) {
778
779                 // Get stacktrace element at current index.
780                 java_handle_t* h = stacktrace_get_StackTraceElement(st, i);
781
782                 if (h == NULL)
783                         return NULL;
784
785                 // Store stacktrace element in array.
786                 array_objectarray_element_set(oa, i, h);
787         }
788
789         return oa;
790 }
791 #endif
792
793
794 /* stacktrace_get_caller_class *************************************************
795
796    Get the class on the stack at the given depth.  This function skips
797    various special classes or methods.
798
799    ARGUMENTS:
800        depth ... depth to get caller class of
801
802    RETURN:
803        caller class
804
805 *******************************************************************************/
806
807 #if defined(ENABLE_JAVASE)
808 classinfo *stacktrace_get_caller_class(int depth)
809 {
810         stackframeinfo_t *sfi;
811         stackframeinfo_t  tmpsfi;
812         methodinfo       *m;
813         classinfo        *c;
814         int               i;
815
816 #if !defined(NDEBUG)
817         if (opt_DebugStackTrace)
818                 log_println("[stacktrace_get_caller_class]");
819 #endif
820
821         /* Get the stackframeinfo of the current thread. */
822
823         sfi = threads_get_current_stackframeinfo();
824
825         /* Iterate over the whole stack until we reached the requested
826            depth. */
827
828         i = 0;
829
830         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
831                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
832                  stacktrace_stackframeinfo_next(&tmpsfi)) {
833
834                 m = tmpsfi.code->m;
835                 c = m->clazz;
836
837                 /* Skip builtin methods. */
838
839                 if (m->flags & ACC_METHOD_BUILTIN)
840                         continue;
841
842 #if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
843                 /* NOTE: See hotspot/src/share/vm/runtime/vframe.cpp
844                    (vframeStreamCommon::security_get_caller_frame). */
845
846                 /* This is java.lang.reflect.Method.invoke(), skip it. */
847
848                 if (m == method_java_lang_reflect_Method_invoke)
849                         continue;
850
851                 /* This is an auxiliary frame, skip it. */
852
853                 if (class_issubclass(c, class_sun_reflect_MagicAccessorImpl))
854                         continue;
855 #endif
856
857                 /* We reached the requested depth. */
858
859                 if (i >= depth)
860                         return c;
861
862                 i++;
863         }
864
865         return NULL;
866 }
867 #endif
868
869
870 /* stacktrace_first_nonnull_classloader ****************************************
871
872    Returns the first non-null (user-defined) classloader on the stack.
873    If none is found NULL is returned.
874
875    RETURN:
876        classloader
877
878 *******************************************************************************/
879
880 classloader_t *stacktrace_first_nonnull_classloader(void)
881 {
882         stackframeinfo_t *sfi;
883         stackframeinfo_t  tmpsfi;
884         methodinfo       *m;
885         classloader_t    *cl;
886
887 #if !defined(NDEBUG)
888         if (opt_DebugStackTrace)
889                 log_println("[stacktrace_first_nonnull_classloader]");
890 #endif
891
892         /* Get the stackframeinfo of the current thread. */
893
894         sfi = threads_get_current_stackframeinfo();
895
896         /* Iterate over the whole stack. */
897
898         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
899                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
900                  stacktrace_stackframeinfo_next(&tmpsfi)) {
901
902                 m  = tmpsfi.code->m;
903                 cl = class_get_classloader(m->clazz);
904
905                 if (cl != NULL)
906                         return cl;
907         }
908
909         return NULL;
910 }
911
912
913 /* stacktrace_getClassContext **************************************************
914
915    Creates a Class context array.
916
917    RETURN VALUE:
918       the array of java.lang.Class objects, or
919           NULL if an exception has been thrown
920
921 *******************************************************************************/
922
923 java_handle_objectarray_t *stacktrace_getClassContext(void)
924 {
925         stackframeinfo_t           *sfi;
926         stackframeinfo_t            tmpsfi;
927         int                         depth;
928         java_handle_objectarray_t  *oa;
929         java_object_t             **data;
930         int                         i;
931         methodinfo                 *m;
932
933         CYCLES_STATS_DECLARE_AND_START
934
935 #if !defined(NDEBUG)
936         if (opt_DebugStackTrace)
937                 log_println("[stacktrace_getClassContext]");
938 #endif
939
940         sfi = threads_get_current_stackframeinfo();
941
942         /* Get the depth of the current stack. */
943
944         depth = stacktrace_depth(sfi);
945
946         /* The first stackframe corresponds to the method whose
947            implementation calls this native function.  We remove that
948            entry. */
949
950         depth--;
951         stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
952         stacktrace_stackframeinfo_next(&tmpsfi);
953
954         /* Allocate the Class array. */
955
956         oa = builtin_anewarray(depth, class_java_lang_Class);
957
958         if (oa == NULL) {
959                 CYCLES_STATS_END(stacktrace_getClassContext);
960
961                 return NULL;
962         }
963
964         /* Fill the Class array from the stacktrace list. */
965
966         LLNI_CRITICAL_START;
967
968         data = LLNI_array_data(oa);
969
970         /* Iterate over the whole stack. */
971
972         i = 0;
973
974         for (;
975                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
976                  stacktrace_stackframeinfo_next(&tmpsfi)) {
977                 /* Get methodinfo. */
978
979                 m = tmpsfi.code->m;
980
981                 /* Skip builtin methods. */
982
983                 if (m->flags & ACC_METHOD_BUILTIN)
984                         continue;
985
986                 /* Store the class in the array. */
987
988                 data[i] = (java_object_t *) m->clazz;
989
990                 i++;
991         }
992
993         LLNI_CRITICAL_END;
994
995         CYCLES_STATS_END(stacktrace_getClassContext)
996
997         return oa;
998 }
999
1000
1001 /* stacktrace_getCurrentClass **************************************************
1002
1003    Find the current class by walking the stack trace.
1004
1005    Quote from the JNI documentation:
1006          
1007    In the Java 2 Platform, FindClass locates the class loader
1008    associated with the current native method.  If the native code
1009    belongs to a system class, no class loader will be
1010    involved. Otherwise, the proper class loader will be invoked to
1011    load and link the named class. When FindClass is called through the
1012    Invocation Interface, there is no current native method or its
1013    associated class loader. In that case, the result of
1014    ClassLoader.getBaseClassLoader is used."
1015
1016 *******************************************************************************/
1017
1018 #if defined(ENABLE_JAVASE)
1019 classinfo *stacktrace_get_current_class(void)
1020 {
1021         stackframeinfo_t *sfi;
1022         stackframeinfo_t  tmpsfi;
1023         methodinfo       *m;
1024
1025         CYCLES_STATS_DECLARE_AND_START;
1026
1027 #if !defined(NDEBUG)
1028         if (opt_DebugStackTrace)
1029                 log_println("[stacktrace_get_current_class]");
1030 #endif
1031
1032         /* Get the stackframeinfo of the current thread. */
1033
1034         sfi = threads_get_current_stackframeinfo();
1035
1036         /* If the stackframeinfo is NULL then FindClass is called through
1037            the Invocation Interface and we return NULL */
1038
1039         if (sfi == NULL) {
1040                 CYCLES_STATS_END(stacktrace_getCurrentClass);
1041
1042                 return NULL;
1043         }
1044
1045         /* Iterate over the whole stack. */
1046
1047         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1048                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1049                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1050                 /* Get the methodinfo. */
1051
1052                 m = tmpsfi.code->m;
1053
1054                 if (m->clazz == class_java_security_PrivilegedAction) {
1055                         CYCLES_STATS_END(stacktrace_getCurrentClass);
1056
1057                         return NULL;
1058                 }
1059
1060                 if (m->clazz != NULL) {
1061                         CYCLES_STATS_END(stacktrace_getCurrentClass);
1062
1063                         return m->clazz;
1064                 }
1065         }
1066
1067         /* No Java method found on the stack. */
1068
1069         CYCLES_STATS_END(stacktrace_getCurrentClass);
1070
1071         return NULL;
1072 }
1073 #endif /* ENABLE_JAVASE */
1074
1075
1076 /* stacktrace_get_stack ********************************************************
1077
1078    Create a 2-dimensional array for java.security.VMAccessControler.
1079
1080    RETURN VALUE:
1081       the arrary, or
1082          NULL if an exception has been thrown
1083
1084 *******************************************************************************/
1085
1086 #if defined(ENABLE_JAVASE) && defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
1087 java_handle_objectarray_t *stacktrace_get_stack(void)
1088 {
1089         stackframeinfo_t          *sfi;
1090         stackframeinfo_t           tmpsfi;
1091         int                        depth;
1092         java_handle_objectarray_t *oa;
1093         java_handle_objectarray_t *classes;
1094         java_handle_objectarray_t *methodnames;
1095         methodinfo                *m;
1096         java_handle_t             *string;
1097         int                        i;
1098
1099         CYCLES_STATS_DECLARE_AND_START
1100
1101 #if !defined(NDEBUG)
1102         if (opt_DebugStackTrace)
1103                 log_println("[stacktrace_get_stack]");
1104 #endif
1105
1106         /* Get the stackframeinfo of the current thread. */
1107
1108         sfi = threads_get_current_stackframeinfo();
1109
1110         /* Get the depth of the current stack. */
1111
1112         depth = stacktrace_depth(sfi);
1113
1114         if (depth == 0)
1115                 return NULL;
1116
1117         /* Allocate the required arrays. */
1118
1119         oa = builtin_anewarray(2, arrayclass_java_lang_Object);
1120
1121         if (oa == NULL)
1122                 goto return_NULL;
1123
1124         classes = builtin_anewarray(depth, class_java_lang_Class);
1125
1126         if (classes == NULL)
1127                 goto return_NULL;
1128
1129         methodnames = builtin_anewarray(depth, class_java_lang_String);
1130
1131         if (methodnames == NULL)
1132                 goto return_NULL;
1133
1134         /* Set up the 2-dimensional array. */
1135
1136         array_objectarray_element_set(oa, 0, (java_handle_t *) classes);
1137         array_objectarray_element_set(oa, 1, (java_handle_t *) methodnames);
1138
1139         /* Iterate over the whole stack. */
1140         /* TODO We should use a critical section here to speed things
1141            up. */
1142
1143         i = 0;
1144
1145         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1146                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1147                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1148                 /* Get the methodinfo. */
1149
1150                 m = tmpsfi.code->m;
1151
1152                 /* Skip builtin methods. */
1153
1154                 if (m->flags & ACC_METHOD_BUILTIN)
1155                         continue;
1156
1157                 /* Store the class in the array. */
1158                 /* NOTE: We use a LLNI-macro here, because a classinfo is not
1159                    a handle. */
1160
1161                 LLNI_array_direct(classes, i) = (java_object_t *) m->clazz;
1162
1163                 /* Store the name in the array. */
1164
1165                 string = javastring_new(m->name);
1166
1167                 if (string == NULL)
1168                         goto return_NULL;
1169
1170                 array_objectarray_element_set(methodnames, i, string);
1171
1172                 i++;
1173         }
1174
1175         CYCLES_STATS_END(stacktrace_get_stack)
1176
1177         return oa;
1178
1179 return_NULL:
1180         CYCLES_STATS_END(stacktrace_get_stack)
1181
1182         return NULL;
1183 }
1184 #endif
1185
1186
1187 /* stacktrace_print_entry ****************************************************
1188
1189    Print line for a stacktrace entry.
1190
1191    ARGUMENTS:
1192        m ............ methodinfo of the entry
1193        linenumber ... linenumber of the entry
1194
1195 *******************************************************************************/
1196
1197 static void stacktrace_print_entry(methodinfo *m, int32_t linenumber)
1198 {
1199         /* Sanity check. */
1200
1201         assert(m != NULL);
1202
1203         printf("\tat ");
1204
1205         if (m->flags & ACC_METHOD_BUILTIN)
1206                 printf("NULL");
1207         else
1208                 utf_display_printable_ascii_classname(m->clazz->name);
1209
1210         printf(".");
1211         utf_display_printable_ascii(m->name);
1212         utf_display_printable_ascii(m->descriptor);
1213
1214         if (m->flags & ACC_NATIVE) {
1215                 puts("(Native Method)");
1216         }
1217         else {
1218                 if (m->flags & ACC_METHOD_BUILTIN) {
1219                         puts("(builtin)");
1220                 }
1221                 else {
1222                         printf("(");
1223                         utf_display_printable_ascii(m->clazz->sourcefile);
1224                         printf(":%d)\n", linenumber);
1225                 }
1226         }
1227
1228         fflush(stdout);
1229 }
1230
1231
1232 /* stacktrace_print ************************************************************
1233
1234    Print the given stacktrace with CACAO intern methods only (no Java
1235    code required).
1236
1237    This method is used by stacktrace_dump_trace and
1238    builtin_trace_exception.
1239
1240    IN:
1241        st ... stacktrace to print
1242
1243 *******************************************************************************/
1244
1245 void stacktrace_print(stacktrace_t *st)
1246 {
1247         stacktrace_entry_t *ste;
1248         methodinfo         *m;
1249         int32_t             linenumber;
1250         int                 i;
1251
1252         ste = &(st->entries[0]);
1253
1254         for (i = 0; i < st->length; i++, ste++) {
1255                 m = ste->code->m;
1256
1257                 /* Get the line number. */
1258
1259                 linenumber = ste->code->linenumbertable->find(&m, ste->pc);
1260
1261                 stacktrace_print_entry(m, linenumber);
1262         }
1263 }
1264
1265
1266 /* stacktrace_print_current ****************************************************
1267
1268    Print the current stacktrace of the current thread.
1269
1270    NOTE: This function prints all frames of the stacktrace and does
1271    not skip frames like stacktrace_get.
1272
1273 *******************************************************************************/
1274
1275 void stacktrace_print_current(void)
1276 {
1277         stackframeinfo_t *sfi;
1278         stackframeinfo_t  tmpsfi;
1279         codeinfo         *code;
1280         methodinfo       *m;
1281         int32_t           linenumber;
1282
1283         sfi = threads_get_current_stackframeinfo();
1284
1285         if (sfi == NULL) {
1286                 puts("\t<<No stacktrace available>>");
1287                 fflush(stdout);
1288                 return;
1289         }
1290
1291         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1292                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1293                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1294                 /* Get the methodinfo. */
1295
1296                 code = tmpsfi.code;
1297                 m    = code->m;
1298
1299                 // Get the line number.
1300                 linenumber = code->linenumbertable->find(&m, tmpsfi.xpc);
1301
1302                 stacktrace_print_entry(m, linenumber);
1303         }
1304 }
1305
1306
1307 /**
1308  * Creates a stacktrace for the given thread.
1309  *
1310  * @param t Given thread.
1311  * @return Current stacktrace of the given thread.
1312  *
1313  * XXX: Creation of the stacktrace starts at the most recent
1314  * stackframeinfo block. If the thread is not inside the native
1315  * world, the created stacktrace is not complete!
1316  */
1317 #if defined(ENABLE_THREADS)
1318 stacktrace_t* stacktrace_get_of_thread(threadobject* t)
1319 {
1320         stackframeinfo_t*        sfi;
1321         java_handle_bytearray_t* ba;
1322         stacktrace_t*            st;
1323
1324         sfi = t->_stackframeinfo;
1325         ba  = stacktrace_get(sfi);
1326
1327         if (ba == NULL)
1328                 return NULL;
1329
1330         st  = (stacktrace_t*) LLNI_array_data(ba);
1331
1332         return st;
1333 }
1334 #endif
1335
1336
1337 /* stacktrace_print_of_thread **************************************************
1338
1339    Print the current stacktrace of the given thread.
1340
1341    ARGUMENTS:
1342        t ... thread
1343
1344 *******************************************************************************/
1345
1346 #if defined(ENABLE_THREADS)
1347 void stacktrace_print_of_thread(threadobject *t)
1348 {
1349         stackframeinfo_t *sfi;
1350         stackframeinfo_t  tmpsfi;
1351         codeinfo         *code;
1352         methodinfo       *m;
1353         int32_t           linenumber;
1354
1355         /* Build a stacktrace for the passed thread. */
1356
1357         sfi = t->_stackframeinfo;
1358         
1359         if (sfi == NULL) {
1360                 puts("\t<<No stacktrace available>>");
1361                 fflush(stdout);
1362                 return;
1363         }
1364
1365         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1366                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1367                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1368                 /* Get the methodinfo. */
1369
1370                 code = tmpsfi.code;
1371                 m    = code->m;
1372
1373                 // Get the line number.
1374                 linenumber = code->linenumbertable->find(&m, tmpsfi.xpc);
1375
1376                 stacktrace_print_entry(m, linenumber);
1377         }
1378 }
1379 #endif
1380
1381
1382 /* stacktrace_print_exception **************************************************
1383
1384    Print the stacktrace of a given exception (more or less a wrapper
1385    to stacktrace_print).
1386
1387    IN:
1388        h ... handle of exception to print
1389
1390 *******************************************************************************/
1391
1392 void stacktrace_print_exception(java_handle_t *h)
1393 {
1394         if (h == NULL)
1395                 return;
1396
1397         java_lang_Throwable t(h);
1398
1399         /* now print the stacktrace */
1400
1401 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
1402
1403         java_lang_VMThrowable vmt(t.get_vmState());
1404         java_handle_bytearray_t* backtrace = vmt.get_vmdata();
1405
1406 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) || defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
1407
1408         java_handle_bytearray_t* backtrace = t.get_backtrace();
1409
1410 #else
1411 # error unknown classpath configuration
1412 #endif
1413
1414         // Sanity check.
1415
1416         assert(backtrace != NULL);
1417
1418         /* We need a critical section here as we use the byte-array data
1419            pointer directly. */
1420
1421         LLNI_CRITICAL_START;
1422         
1423         stacktrace_t* st = (stacktrace_t*) LLNI_array_data(backtrace);
1424
1425         stacktrace_print(st);
1426
1427         LLNI_CRITICAL_END;
1428 }
1429
1430
1431 #if defined(ENABLE_CYCLES_STATS)
1432 void stacktrace_print_cycles_stats(FILE *file)
1433 {
1434         CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead, file);
1435         CYCLES_STATS_PRINT(stacktrace_get,               file);
1436         CYCLES_STATS_PRINT(stacktrace_getClassContext ,  file);
1437         CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,  file);
1438         CYCLES_STATS_PRINT(stacktrace_get_stack,         file);
1439 }
1440 #endif
1441
1442 } // extern "C"
1443
1444
1445 /*
1446  * These are local overrides for various environment variables in Emacs.
1447  * Please do not remove this and leave it at the end of the file, where
1448  * Emacs will automagically detect them.
1449  * ---------------------------------------------------------------------
1450  * Local variables:
1451  * mode: c++
1452  * indent-tabs-mode: t
1453  * c-basic-offset: 4
1454  * tab-width: 4
1455  * End:
1456  * vim:noexpandtab:sw=4:ts=4:
1457  */