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