* src/vm/array.hpp: Implemented array access classes in C++.
[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         int32_t             ba_size;
522         stacktrace_t       *st;
523         stacktrace_entry_t *ste;
524         methodinfo         *m;
525         bool                skip_fillInStackTrace;
526         bool                skip_init;
527
528         CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
529
530 #if !defined(NDEBUG)
531         if (opt_DebugStackTrace)
532                 log_println("[stacktrace_get]");
533 #endif
534
535         skip_fillInStackTrace = true;
536         skip_init             = true;
537
538         depth = stacktrace_depth(sfi);
539
540         if (depth == 0)
541                 return NULL;
542
543         /* Allocate memory from the GC heap and copy the stacktrace
544            buffer. */
545         /* ATTENTION: Use a Java byte-array for this to not confuse the
546            GC. */
547         /* FIXME: We waste some memory here as we skip some entries
548            later. */
549
550         ba_size = sizeof(stacktrace_t) + sizeof(stacktrace_entry_t) * depth;
551
552         ByteArray ba(ba_size);
553
554         if (ba.is_null())
555                 goto return_NULL;
556
557         /* Get a stacktrace entry pointer. */
558         /* ATTENTION: We need a critical section here because we use the
559            byte-array data pointer directly. */
560
561         LLNI_CRITICAL_START;
562
563         st = (stacktrace_t *) ba.get_raw_data_ptr();
564
565         ste = st->entries;
566
567         /* Iterate over the whole stack. */
568
569         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
570                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
571                  stacktrace_stackframeinfo_next(&tmpsfi)) {
572                 /* Get the methodinfo. */
573
574                 m = tmpsfi.code->m;
575
576                 /* Skip builtin methods. */
577
578                 if (m->flags & ACC_METHOD_BUILTIN)
579                         continue;
580
581                 /* This logic is taken from
582                    hotspot/src/share/vm/classfile/javaClasses.cpp
583                    (java_lang_Throwable::fill_in_stack_trace). */
584
585                 if (skip_fillInStackTrace == true) {
586                         /* Check "fillInStackTrace" only once, so we negate the
587                            flag after the first time check. */
588
589 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
590                         /* For GNU Classpath we also need to skip
591                            VMThrowable.fillInStackTrace(). */
592
593                         if ((m->clazz == class_java_lang_VMThrowable) &&
594                                 (m->name  == utf_fillInStackTrace))
595                                 continue;
596 #endif
597
598                         skip_fillInStackTrace = false;
599
600                         if (m->name == utf_fillInStackTrace)
601                                 continue;
602                 }
603
604                 /* Skip <init> methods of the exceptions klass.  If there is
605                    <init> methods that belongs to a superclass of the
606                    exception we are going to skipping them in stack trace. */
607
608                 if (skip_init == true) {
609                         if ((m->name == utf_init) &&
610                                 (class_issubclass(m->clazz, class_java_lang_Throwable))) {
611                                 continue;
612                         }
613                         else {
614                                 /* If no "Throwable.init()" method found, we stop
615                                    checking it next time. */
616
617                                 skip_init = false;
618                         }
619                 }
620
621                 /* Store the stacktrace entry and increment the pointer. */
622
623                 ste->code = tmpsfi.code;
624                 ste->pc   = tmpsfi.xpc;
625
626                 ste++;
627         }
628
629         /* Store the number of entries in the stacktrace structure. */
630
631         st->length = ste - st->entries;
632
633         LLNI_CRITICAL_END;
634
635         /* release dump memory */
636
637 /*      dump_release(dumpsize); */
638
639         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
640                                                                    stacktrace_overhead)
641         return ba.get_handle();
642
643 return_NULL:
644 /*      dump_release(dumpsize); */
645
646         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
647                                                                    stacktrace_overhead)
648
649         return NULL;
650 }
651
652
653 /* stacktrace_get_current ******************************************************
654
655    Builds and returns a stacktrace from the current thread and returns
656    the stacktrace structure wrapped in a Java byte-array to not
657    confuse the GC.
658
659    RETURN:
660        stacktrace as Java byte-array
661
662 *******************************************************************************/
663
664 java_handle_bytearray_t *stacktrace_get_current(void)
665 {
666         stackframeinfo_t        *sfi;
667         java_handle_bytearray_t *ba;
668
669         sfi = threads_get_current_stackframeinfo();
670         ba  = stacktrace_get(sfi);
671
672         return ba;
673 }
674
675
676 /**
677  * Creates a java.lang.StackTraceElement for one element of the given
678  * stacktrace.
679  *
680  * @param st Given stacktrace.
681  * @param index Index of element inside stacktrace.
682  * @return The filled StackTraceElement object.
683  */
684 #if defined(ENABLE_JAVASE)
685 java_handle_t* stacktrace_get_StackTraceElement(stacktrace_t* st, int32_t index)
686 {
687         assert(st != NULL);
688
689         if ((index < 0) || (index >= st->length)) {
690                 /* XXX This should be an IndexOutOfBoundsException (check this
691                    again). */
692                 exceptions_throw_arrayindexoutofboundsexception();
693                 return NULL;
694         }
695
696         // Get the stacktrace entry.
697         stacktrace_entry_t* ste = &(st->entries[index]);
698
699         // Get the codeinfo, methodinfo and classinfo.
700         codeinfo*   code = ste->code;
701         methodinfo* m    = code->m;
702         classinfo*  c    = m->clazz;
703
704         // Get filename.
705         java_handle_t* filename;
706
707         if (!(m->flags & ACC_NATIVE)) {
708                 if (c->sourcefile != NULL)
709                         filename = javastring_new(c->sourcefile);
710                 else
711                         filename = NULL;
712         }
713         else
714                 filename = NULL;
715
716         // Get line number.
717         int32_t linenumber;
718
719         if (m->flags & ACC_NATIVE) {
720 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
721                 linenumber = -1;
722 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
723                 linenumber = -2;
724 #else
725 # error unknown classpath configuration
726 #endif
727         }
728         else {
729                 // FIXME linenumbertable->find could change the methodinfo
730                 // pointer when hitting an inlined method.
731                 linenumber = code->linenumbertable->find(&m, ste->pc);
732                 linenumber = (linenumber == 0) ? -1 : linenumber;
733         }
734
735         // Get declaring class name.
736         java_handle_t* declaringclass = class_get_classname(c);
737
738 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
739         // Allocate a new StackTraceElement object.
740         java_handle_t* h = builtin_new(class_java_lang_StackTraceElement);
741
742         if (h == NULL)
743                         return NULL;
744
745         java_lang_StackTraceElement jlste(h, filename, linenumber, declaringclass, javastring_new(m->name), ((m->flags & ACC_NATIVE) ? 1 : 0));
746 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
747         // Allocate a new StackTraceElement object.
748         java_lang_StackTraceElement jlste(declaringclass, javastring_new(m->name), filename, linenumber);
749
750         if (jlste.is_null())
751                 return NULL;
752 #else
753 # error unknown classpath configuration
754 #endif
755
756         return jlste.get_handle();
757 }
758 #endif
759
760
761 /**
762  * Creates a complete array of java.lang.StackTraceElement objects
763  * for the given stacktrace.
764  *
765  * @param st Given stacktrace.
766  * @return Array of filled StackTraceElement objects.
767  */
768 #if defined(ENABLE_JAVASE)
769 java_handle_objectarray_t* stacktrace_get_StackTraceElements(stacktrace_t* st)
770 {
771         // Get length of stacktrace. If stacktrace is not available
772         // an empty array should be returned.
773         int32_t length = (st != NULL) ? st->length : 0;
774
775         // Create the stacktrace element array.
776         ObjectArray oa(length, class_java_lang_StackTraceElement);
777
778         if (oa.is_null())
779                 return NULL;
780
781         // Iterate over all stacktrace elements.
782         for (int i = 0; i < length; i++) {
783
784                 // Get stacktrace element at current index.
785                 java_handle_t* h = stacktrace_get_StackTraceElement(st, i);
786
787                 if (h == NULL)
788                         return NULL;
789
790                 // Store stacktrace element in array.
791                 oa.set_element(i, h);
792         }
793
794         return oa.get_handle();
795 }
796 #endif
797
798
799 /* stacktrace_get_caller_class *************************************************
800
801    Get the class on the stack at the given depth.  This function skips
802    various special classes or methods.
803
804    ARGUMENTS:
805        depth ... depth to get caller class of
806
807    RETURN:
808        caller class
809
810 *******************************************************************************/
811
812 #if defined(ENABLE_JAVASE)
813 classinfo *stacktrace_get_caller_class(int depth)
814 {
815         stackframeinfo_t *sfi;
816         stackframeinfo_t  tmpsfi;
817         methodinfo       *m;
818         classinfo        *c;
819         int               i;
820
821 #if !defined(NDEBUG)
822         if (opt_DebugStackTrace)
823                 log_println("[stacktrace_get_caller_class]");
824 #endif
825
826         /* Get the stackframeinfo of the current thread. */
827
828         sfi = threads_get_current_stackframeinfo();
829
830         /* Iterate over the whole stack until we reached the requested
831            depth. */
832
833         i = 0;
834
835         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
836                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
837                  stacktrace_stackframeinfo_next(&tmpsfi)) {
838
839                 m = tmpsfi.code->m;
840                 c = m->clazz;
841
842                 /* Skip builtin methods. */
843
844                 if (m->flags & ACC_METHOD_BUILTIN)
845                         continue;
846
847 #if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
848                 /* NOTE: See hotspot/src/share/vm/runtime/vframe.cpp
849                    (vframeStreamCommon::security_get_caller_frame). */
850
851                 /* This is java.lang.reflect.Method.invoke(), skip it. */
852
853                 if (m == method_java_lang_reflect_Method_invoke)
854                         continue;
855
856                 /* This is an auxiliary frame, skip it. */
857
858                 if (class_issubclass(c, class_sun_reflect_MagicAccessorImpl))
859                         continue;
860 #endif
861
862                 /* We reached the requested depth. */
863
864                 if (i >= depth)
865                         return c;
866
867                 i++;
868         }
869
870         return NULL;
871 }
872 #endif
873
874
875 /* stacktrace_first_nonnull_classloader ****************************************
876
877    Returns the first non-null (user-defined) classloader on the stack.
878    If none is found NULL is returned.
879
880    RETURN:
881        classloader
882
883 *******************************************************************************/
884
885 classloader_t *stacktrace_first_nonnull_classloader(void)
886 {
887         stackframeinfo_t *sfi;
888         stackframeinfo_t  tmpsfi;
889         methodinfo       *m;
890         classloader_t    *cl;
891
892 #if !defined(NDEBUG)
893         if (opt_DebugStackTrace)
894                 log_println("[stacktrace_first_nonnull_classloader]");
895 #endif
896
897         /* Get the stackframeinfo of the current thread. */
898
899         sfi = threads_get_current_stackframeinfo();
900
901         /* Iterate over the whole stack. */
902
903         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
904                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
905                  stacktrace_stackframeinfo_next(&tmpsfi)) {
906
907                 m  = tmpsfi.code->m;
908                 cl = class_get_classloader(m->clazz);
909
910                 if (cl != NULL)
911                         return cl;
912         }
913
914         return NULL;
915 }
916
917
918 /* stacktrace_getClassContext **************************************************
919
920    Creates a Class context array.
921
922    RETURN VALUE:
923       the array of java.lang.Class objects, or
924           NULL if an exception has been thrown
925
926 *******************************************************************************/
927
928 java_handle_objectarray_t *stacktrace_getClassContext(void)
929 {
930         stackframeinfo_t           *sfi;
931         stackframeinfo_t            tmpsfi;
932         int                         depth;
933         int                         i;
934         methodinfo                 *m;
935
936         CYCLES_STATS_DECLARE_AND_START
937
938 #if !defined(NDEBUG)
939         if (opt_DebugStackTrace)
940                 log_println("[stacktrace_getClassContext]");
941 #endif
942
943         sfi = threads_get_current_stackframeinfo();
944
945         /* Get the depth of the current stack. */
946
947         depth = stacktrace_depth(sfi);
948
949         /* The first stackframe corresponds to the method whose
950            implementation calls this native function.  We remove that
951            entry. */
952
953         depth--;
954         stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
955         stacktrace_stackframeinfo_next(&tmpsfi);
956
957         /* Allocate the Class array. */
958
959         ClassArray ca(depth);
960
961         if (ca.is_null()) {
962                 CYCLES_STATS_END(stacktrace_getClassContext);
963
964                 return NULL;
965         }
966
967         /* Fill the Class array from the stacktrace list. */
968         /* Iterate over the whole stack. */
969
970         i = 0;
971
972         for (;
973                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
974                  stacktrace_stackframeinfo_next(&tmpsfi)) {
975                 /* Get methodinfo. */
976
977                 m = tmpsfi.code->m;
978
979                 /* Skip builtin methods. */
980
981                 if (m->flags & ACC_METHOD_BUILTIN)
982                         continue;
983
984                 /* Store the class in the array. */
985
986                 ca.set_element(i, m->clazz);
987
988                 i++;
989         }
990
991         LLNI_CRITICAL_END;
992
993         CYCLES_STATS_END(stacktrace_getClassContext)
994
995         return ca.get_handle();
996 }
997
998
999 /* stacktrace_getCurrentClass **************************************************
1000
1001    Find the current class by walking the stack trace.
1002
1003    Quote from the JNI documentation:
1004          
1005    In the Java 2 Platform, FindClass locates the class loader
1006    associated with the current native method.  If the native code
1007    belongs to a system class, no class loader will be
1008    involved. Otherwise, the proper class loader will be invoked to
1009    load and link the named class. When FindClass is called through the
1010    Invocation Interface, there is no current native method or its
1011    associated class loader. In that case, the result of
1012    ClassLoader.getBaseClassLoader is used."
1013
1014 *******************************************************************************/
1015
1016 #if defined(ENABLE_JAVASE)
1017 classinfo *stacktrace_get_current_class(void)
1018 {
1019         stackframeinfo_t *sfi;
1020         stackframeinfo_t  tmpsfi;
1021         methodinfo       *m;
1022
1023         CYCLES_STATS_DECLARE_AND_START;
1024
1025 #if !defined(NDEBUG)
1026         if (opt_DebugStackTrace)
1027                 log_println("[stacktrace_get_current_class]");
1028 #endif
1029
1030         /* Get the stackframeinfo of the current thread. */
1031
1032         sfi = threads_get_current_stackframeinfo();
1033
1034         /* If the stackframeinfo is NULL then FindClass is called through
1035            the Invocation Interface and we return NULL */
1036
1037         if (sfi == NULL) {
1038                 CYCLES_STATS_END(stacktrace_getCurrentClass);
1039
1040                 return NULL;
1041         }
1042
1043         /* Iterate over the whole stack. */
1044
1045         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1046                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1047                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1048                 /* Get the methodinfo. */
1049
1050                 m = tmpsfi.code->m;
1051
1052                 if (m->clazz == class_java_security_PrivilegedAction) {
1053                         CYCLES_STATS_END(stacktrace_getCurrentClass);
1054
1055                         return NULL;
1056                 }
1057
1058                 if (m->clazz != NULL) {
1059                         CYCLES_STATS_END(stacktrace_getCurrentClass);
1060
1061                         return m->clazz;
1062                 }
1063         }
1064
1065         /* No Java method found on the stack. */
1066
1067         CYCLES_STATS_END(stacktrace_getCurrentClass);
1068
1069         return NULL;
1070 }
1071 #endif /* ENABLE_JAVASE */
1072
1073
1074 /* stacktrace_get_stack ********************************************************
1075
1076    Create a 2-dimensional array for java.security.VMAccessControler.
1077
1078    RETURN VALUE:
1079       the arrary, or
1080          NULL if an exception has been thrown
1081
1082 *******************************************************************************/
1083
1084 #if defined(ENABLE_JAVASE) && defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
1085 java_handle_objectarray_t *stacktrace_get_stack(void)
1086 {
1087         stackframeinfo_t *sfi;
1088         stackframeinfo_t  tmpsfi;
1089         int               depth;
1090         methodinfo       *m;
1091         java_handle_t    *string;
1092         int               i;
1093
1094         CYCLES_STATS_DECLARE_AND_START
1095
1096 #if !defined(NDEBUG)
1097         if (opt_DebugStackTrace)
1098                 log_println("[stacktrace_get_stack]");
1099 #endif
1100
1101         /* Get the stackframeinfo of the current thread. */
1102
1103         sfi = threads_get_current_stackframeinfo();
1104
1105         /* Get the depth of the current stack. */
1106
1107         depth = stacktrace_depth(sfi);
1108
1109         if (depth == 0)
1110                 return NULL;
1111
1112         /* Allocate the required arrays. */
1113
1114         ObjectArray oa(2, arrayclass_java_lang_Object);
1115         ClassArray  classes(depth);
1116         ObjectArray methodnames(depth, class_java_lang_String);
1117
1118         if (oa.is_null())
1119                 goto return_NULL;
1120
1121         if (classes.is_null())
1122                 goto return_NULL;
1123
1124         if (methodnames.is_null())
1125                 goto return_NULL;
1126
1127         /* Set up the 2-dimensional array. */
1128
1129         oa.set_element(0, (java_handle_t *) classes.get_handle());
1130         oa.set_element(1, (java_handle_t *) methodnames.get_handle());
1131
1132         /* Iterate over the whole stack. */
1133         /* TODO We should use a critical section here to speed things
1134            up. */
1135
1136         i = 0;
1137
1138         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1139                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1140                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1141                 /* Get the methodinfo. */
1142
1143                 m = tmpsfi.code->m;
1144
1145                 /* Skip builtin methods. */
1146
1147                 if (m->flags & ACC_METHOD_BUILTIN)
1148                         continue;
1149
1150                 /* Store the class in the array. */
1151
1152                 classes.set_element(i, m->clazz);
1153
1154                 /* Store the name in the array. */
1155
1156                 string = javastring_new(m->name);
1157
1158                 if (string == NULL)
1159                         goto return_NULL;
1160
1161                 methodnames.set_element(i, string);
1162
1163                 i++;
1164         }
1165
1166         CYCLES_STATS_END(stacktrace_get_stack)
1167
1168         return oa.get_handle();
1169
1170 return_NULL:
1171         CYCLES_STATS_END(stacktrace_get_stack)
1172
1173         return NULL;
1174 }
1175 #endif
1176
1177
1178 /* stacktrace_print_entry ****************************************************
1179
1180    Print line for a stacktrace entry.
1181
1182    ARGUMENTS:
1183        m ............ methodinfo of the entry
1184        linenumber ... linenumber of the entry
1185
1186 *******************************************************************************/
1187
1188 static void stacktrace_print_entry(methodinfo *m, int32_t linenumber)
1189 {
1190         /* Sanity check. */
1191
1192         assert(m != NULL);
1193
1194         printf("\tat ");
1195
1196         if (m->flags & ACC_METHOD_BUILTIN)
1197                 printf("NULL");
1198         else
1199                 utf_display_printable_ascii_classname(m->clazz->name);
1200
1201         printf(".");
1202         utf_display_printable_ascii(m->name);
1203         utf_display_printable_ascii(m->descriptor);
1204
1205         if (m->flags & ACC_NATIVE) {
1206                 puts("(Native Method)");
1207         }
1208         else {
1209                 if (m->flags & ACC_METHOD_BUILTIN) {
1210                         puts("(builtin)");
1211                 }
1212                 else {
1213                         printf("(");
1214                         utf_display_printable_ascii(m->clazz->sourcefile);
1215                         printf(":%d)\n", linenumber);
1216                 }
1217         }
1218
1219         fflush(stdout);
1220 }
1221
1222
1223 /* stacktrace_print ************************************************************
1224
1225    Print the given stacktrace with CACAO intern methods only (no Java
1226    code required).
1227
1228    This method is used by stacktrace_dump_trace and
1229    builtin_trace_exception.
1230
1231    IN:
1232        st ... stacktrace to print
1233
1234 *******************************************************************************/
1235
1236 void stacktrace_print(stacktrace_t *st)
1237 {
1238         stacktrace_entry_t *ste;
1239         methodinfo         *m;
1240         int32_t             linenumber;
1241         int                 i;
1242
1243         ste = &(st->entries[0]);
1244
1245         for (i = 0; i < st->length; i++, ste++) {
1246                 m = ste->code->m;
1247
1248                 /* Get the line number. */
1249
1250                 linenumber = ste->code->linenumbertable->find(&m, ste->pc);
1251
1252                 stacktrace_print_entry(m, linenumber);
1253         }
1254 }
1255
1256
1257 /* stacktrace_print_current ****************************************************
1258
1259    Print the current stacktrace of the current thread.
1260
1261    NOTE: This function prints all frames of the stacktrace and does
1262    not skip frames like stacktrace_get.
1263
1264 *******************************************************************************/
1265
1266 void stacktrace_print_current(void)
1267 {
1268         stackframeinfo_t *sfi;
1269         stackframeinfo_t  tmpsfi;
1270         codeinfo         *code;
1271         methodinfo       *m;
1272         int32_t           linenumber;
1273
1274         sfi = threads_get_current_stackframeinfo();
1275
1276         if (sfi == NULL) {
1277                 puts("\t<<No stacktrace available>>");
1278                 fflush(stdout);
1279                 return;
1280         }
1281
1282         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1283                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1284                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1285                 /* Get the methodinfo. */
1286
1287                 code = tmpsfi.code;
1288                 m    = code->m;
1289
1290                 // Get the line number.
1291                 linenumber = code->linenumbertable->find(&m, tmpsfi.xpc);
1292
1293                 stacktrace_print_entry(m, linenumber);
1294         }
1295 }
1296
1297
1298 /**
1299  * Creates a stacktrace for the given thread.
1300  *
1301  * @param t Given thread.
1302  * @return Current stacktrace of the given thread.
1303  *
1304  * XXX: Creation of the stacktrace starts at the most recent
1305  * stackframeinfo block. If the thread is not inside the native
1306  * world, the created stacktrace is not complete!
1307  */
1308 #if defined(ENABLE_THREADS)
1309 stacktrace_t* stacktrace_get_of_thread(threadobject* t)
1310 {
1311         stackframeinfo_t*        sfi;
1312         java_handle_bytearray_t* stba;
1313         stacktrace_t*            st;
1314
1315         sfi  = t->_stackframeinfo;
1316         stba = stacktrace_get(sfi);
1317
1318         ByteArray ba(stba);
1319
1320         if (ba.is_null())
1321                 return NULL;
1322
1323         st  = (stacktrace_t*) ba.get_raw_data_ptr();
1324
1325         return st;
1326 }
1327 #endif
1328
1329
1330 /* stacktrace_print_of_thread **************************************************
1331
1332    Print the current stacktrace of the given thread.
1333
1334    ARGUMENTS:
1335        t ... thread
1336
1337 *******************************************************************************/
1338
1339 #if defined(ENABLE_THREADS)
1340 void stacktrace_print_of_thread(threadobject *t)
1341 {
1342         stackframeinfo_t *sfi;
1343         stackframeinfo_t  tmpsfi;
1344         codeinfo         *code;
1345         methodinfo       *m;
1346         int32_t           linenumber;
1347
1348         /* Build a stacktrace for the passed thread. */
1349
1350         sfi = t->_stackframeinfo;
1351         
1352         if (sfi == NULL) {
1353                 puts("\t<<No stacktrace available>>");
1354                 fflush(stdout);
1355                 return;
1356         }
1357
1358         for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi);
1359                  stacktrace_stackframeinfo_end_check(&tmpsfi) == false;
1360                  stacktrace_stackframeinfo_next(&tmpsfi)) {
1361                 /* Get the methodinfo. */
1362
1363                 code = tmpsfi.code;
1364                 m    = code->m;
1365
1366                 // Get the line number.
1367                 linenumber = code->linenumbertable->find(&m, tmpsfi.xpc);
1368
1369                 stacktrace_print_entry(m, linenumber);
1370         }
1371 }
1372 #endif
1373
1374
1375 /* stacktrace_print_exception **************************************************
1376
1377    Print the stacktrace of a given exception (more or less a wrapper
1378    to stacktrace_print).
1379
1380    IN:
1381        h ... handle of exception to print
1382
1383 *******************************************************************************/
1384
1385 void stacktrace_print_exception(java_handle_t *h)
1386 {
1387         if (h == NULL)
1388                 return;
1389
1390         java_lang_Throwable t(h);
1391
1392         /* now print the stacktrace */
1393
1394 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
1395
1396         java_lang_VMThrowable vmt(t.get_vmState());
1397         ByteArray backtrace(vmt.get_vmdata());
1398
1399 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) || defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
1400
1401         ByteArray backtrace(t.get_backtrace());
1402
1403 #else
1404 # error unknown classpath configuration
1405 #endif
1406
1407         // Sanity check.
1408
1409         assert(backtrace.is_non_null());
1410
1411         /* We need a critical section here as we use the byte-array data
1412            pointer directly. */
1413
1414         LLNI_CRITICAL_START;
1415         
1416         stacktrace_t* st = (stacktrace_t*) backtrace.get_raw_data_ptr();
1417
1418         stacktrace_print(st);
1419
1420         LLNI_CRITICAL_END;
1421 }
1422
1423
1424 #if defined(ENABLE_CYCLES_STATS)
1425 void stacktrace_print_cycles_stats(FILE *file)
1426 {
1427         CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead, file);
1428         CYCLES_STATS_PRINT(stacktrace_get,               file);
1429         CYCLES_STATS_PRINT(stacktrace_getClassContext ,  file);
1430         CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,  file);
1431         CYCLES_STATS_PRINT(stacktrace_get_stack,         file);
1432 }
1433 #endif
1434
1435 } // extern "C"
1436
1437
1438 /*
1439  * These are local overrides for various environment variables in Emacs.
1440  * Please do not remove this and leave it at the end of the file, where
1441  * Emacs will automagically detect them.
1442  * ---------------------------------------------------------------------
1443  * Local variables:
1444  * mode: c++
1445  * indent-tabs-mode: t
1446  * c-basic-offset: 4
1447  * tab-width: 4
1448  * End:
1449  * vim:noexpandtab:sw=4:ts=4:
1450  */