* Removed all Id tags.
[cacao.git] / src / vm / jit / stacktrace.c
1 /* src/vm/jit/stacktrace.c - machine independent stacktrace system
2
3    Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25 */
26
27
28 #include "config.h"
29
30 #include <assert.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "vm/types.h"
35
36 #include "mm/gc-common.h"
37 #include "mm/memory.h"
38
39 #include "vm/jit/stacktrace.h"
40
41 #include "vm/global.h"                   /* required here for native includes */
42 #include "native/jni.h"
43 #include "native/llni.h"
44 #include "native/include/java_lang_Throwable.h"
45
46 #if defined(WITH_CLASSPATH_GNU)
47 # include "native/include/java_lang_VMThrowable.h"
48 #endif
49
50 #if defined(ENABLE_THREADS)
51 # include "threads/native/threads.h"
52 #else
53 # include "threads/none/threads.h"
54 #endif
55
56 #include "toolbox/logging.h"
57
58 #include "vm/builtin.h"
59 #include "vm/cycles-stats.h"
60 #include "vm/exceptions.h"
61 #include "vm/stringlocal.h"
62 #include "vm/vm.h"
63
64 #include "vm/jit/asmpart.h"
65 #include "vm/jit/codegen-common.h"
66 #include "vm/jit/methodheader.h"
67
68 #include "vmcore/class.h"
69 #include "vmcore/loader.h"
70 #include "vmcore/options.h"
71
72
73 /* global variables ***********************************************************/
74 #if !defined(ENABLE_THREADS)
75 stackframeinfo *_no_threads_stackframeinfo = NULL;
76 #endif
77
78 CYCLES_STATS_DECLARE(stacktrace_overhead        ,100,1)
79 CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace,40,5000)
80 CYCLES_STATS_DECLARE(stacktrace_getClassContext ,40,5000)
81 CYCLES_STATS_DECLARE(stacktrace_getCurrentClass ,40,5000)
82 CYCLES_STATS_DECLARE(stacktrace_getStack        ,40,10000)
83
84
85 /* stacktrace_create_stackframeinfo ********************************************
86
87    Creates an stackframe info structure for inline code in the
88    interpreter.
89
90 *******************************************************************************/
91
92 #if defined(ENABLE_INTRP)
93 void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv, u1 *sp,
94                                                                           u1 *ra)
95 {
96         stackframeinfo **psfi;
97         methodinfo      *m;
98         codeinfo        *code;
99
100         /* get current stackframe info pointer */
101
102         psfi = &STACKFRAMEINFO;
103
104         /* if we don't have pv handy */
105
106         if (pv == NULL) {
107 #if defined(ENABLE_INTRP)
108                 if (opt_intrp)
109                         pv = codegen_get_pv_from_pc(ra);
110                 else
111 #endif
112                         {
113 #if defined(ENABLE_JIT)
114                                 pv = md_codegen_get_pv_from_pc(ra);
115 #endif
116                         }
117         }
118
119         /* get codeinfo pointer from data segment */
120
121         code = *((codeinfo **) (pv + CodeinfoPointer));
122
123         /* For asm_vm_call_method the codeinfo pointer is NULL. */
124
125         m = (code == NULL) ? NULL : code->m;
126
127         /* fill new stackframe info structure */
128
129         sfi->prev   = *psfi;
130         sfi->method = m;
131         sfi->pv     = pv;
132         sfi->sp     = sp;
133         sfi->ra     = ra;
134
135         /* xpc is the same as ra, but is required in stacktrace_create */
136
137         sfi->xpc    = ra;
138
139         /* store new stackframe info pointer */
140
141         *psfi = sfi;
142 }
143 #endif /* defined(ENABLE_INTRP) */
144
145
146 /* stacktrace_create_extern_stackframeinfo *************************************
147
148    Creates an stackframe info structure for an extern exception
149    (hardware or assembler).
150
151 *******************************************************************************/
152
153 void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
154                                                                                          u1 *sp, u1 *ra, u1 *xpc)
155 {
156         stackframeinfo **psfi;
157 #if !defined(__I386__) && !defined(__X86_64__) && !defined(__S390__) && !defined(__M68K__)
158         bool             isleafmethod;
159 #endif
160 #if defined(ENABLE_JIT)
161         s4               framesize;
162 #endif
163
164         /* get current stackframe info pointer */
165
166         psfi = &STACKFRAMEINFO;
167
168         /* sometimes we don't have pv handy (e.g. in asmpart.S:
169        L_asm_call_jit_compiler_exception or in the interpreter). */
170
171         if (pv == NULL) {
172 #if defined(ENABLE_INTRP)
173                 if (opt_intrp)
174                         pv = codegen_get_pv_from_pc(ra);
175                 else
176 #endif
177                         {
178 #if defined(ENABLE_JIT)
179 # if defined(__SPARC_64__)
180                                 pv = md_get_pv_from_stackframe(sp);
181 # else
182                                 pv = md_codegen_get_pv_from_pc(ra);
183 # endif
184 #endif
185                         }
186         }
187
188 #if defined(ENABLE_JIT)
189 # if defined(ENABLE_INTRP)
190         /* When using the interpreter, we pass RA to the function. */
191
192         if (!opt_intrp) {
193 # endif
194 # if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__M68K__)
195                 /* On i386 and x86_64 we always have to get the return address
196                    from the stack. */
197                 /* m68k has return address on stack always */
198                 /* On S390 we use REG_RA as REG_ITMP3, so we have always to get
199                    the RA from stack. */
200
201                 framesize = *((u4 *) (pv + FrameSize));
202
203                 ra = md_stacktrace_get_returnaddress(sp, framesize);
204 # else
205                 /* If the method is a non-leaf function, we need to get the return
206                    address from the stack. For leaf functions the return address
207                    is set correctly. This makes the assembler and the signal
208                    handler code simpler. */
209
210                 isleafmethod = *((s4 *) (pv + IsLeaf));
211
212                 if (!isleafmethod) {
213                         framesize = *((u4 *) (pv + FrameSize));
214
215                         ra = md_stacktrace_get_returnaddress(sp, framesize);
216                 }
217 # endif
218 # if defined(ENABLE_INTRP)
219         }
220 # endif
221 #endif /* defined(ENABLE_JIT) */
222
223         /* fill new stackframe info structure */
224
225         sfi->prev   = *psfi;
226         sfi->method = NULL;
227         sfi->pv     = pv;
228         sfi->sp     = sp;
229         sfi->ra     = ra;
230         sfi->xpc    = xpc;
231
232         /* store new stackframe info pointer */
233
234         *psfi = sfi;
235 }
236
237
238 /* stacktrace_create_native_stackframeinfo *************************************
239
240    Creates a stackframe info structure for a native stub.
241
242 *******************************************************************************/
243
244 void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv,
245                                                                                          u1 *sp, u1 *ra)
246 {
247         stackframeinfo **psfi;
248         methodinfo      *m;
249         codeinfo        *code;
250
251         /* get codeinfo pointer from data segment */
252
253         code = *((codeinfo **) (pv + CodeinfoPointer));
254
255         /* For asm_vm_call_method the codeinfo pointer is NULL. */
256
257         m = (code == NULL) ? NULL : code->m;
258
259         /* get current stackframe info pointer */
260
261         psfi = &STACKFRAMEINFO;
262
263         /* fill new stackframe info structure */
264
265         sfi->prev   = *psfi;
266         sfi->method = m;
267         sfi->pv     = NULL;
268         sfi->sp     = sp;
269         sfi->ra     = ra;
270         sfi->xpc    = NULL;
271
272         /* store new stackframe info pointer */
273
274         *psfi = sfi;
275 }
276
277
278 /* stacktrace_remove_stackframeinfo ********************************************
279
280    Remove the topmost stackframeinfo in the current thread.
281
282 *******************************************************************************/
283
284 void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
285 {
286         stackframeinfo **psfi;
287
288         /* get current stackframe info pointer */
289
290         psfi = &STACKFRAMEINFO;
291
292         /* restore the old pointer */
293
294         *psfi = sfi->prev;
295 }
296
297
298 /* stacktrace_add_entry ********************************************************
299
300    Adds a new entry to the stacktrace buffer.
301
302 *******************************************************************************/
303
304 static void stacktrace_add_entry(stacktracebuffer *stb, methodinfo *m, u2 line)
305 {
306         stacktrace_entry *ste;
307
308         /* check if we already reached the buffer capacity */
309
310         if (stb->used >= stb->capacity) {
311                 /* reallocate new memory */
312
313                 stb->entries = DMREALLOC(stb->entries, stacktrace_entry, stb->capacity,
314                                                                  stb->capacity + STACKTRACE_CAPACITY_INCREMENT);
315
316                 /* set new buffer capacity */
317
318                 stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
319         }
320
321         /* insert the current entry */
322
323         ste = &(stb->entries[stb->used]);
324
325         ste->method     = m;
326         ste->linenumber = line;
327
328         /* increase entries used count */
329
330         stb->used += 1;
331 }
332
333
334 /* stacktrace_add_method *******************************************************
335
336    Add stacktrace entries[1] for the given method to the stacktrace buffer.
337
338    IN:
339        stb.........stacktracebuffer to fill
340            m...........method for which entries should be created
341            pv..........pv of method
342            pc..........position of program counter within the method's code
343
344    OUT:
345        true, if stacktrace entries were successfully created, false otherwise.
346
347    [1] In case of inlined methods there may be more than one stacktrace
348        entry for a codegen-level method. (see doc/inlining_stacktrace.txt)
349
350 *******************************************************************************/
351
352 static bool stacktrace_add_method(stacktracebuffer *stb, methodinfo *m, u1 *pv,
353                                                                   u1 *pc)
354 {
355         codeinfo *code;                     /* compiled realization of method     */
356         s4        linenumber;
357
358         /* find the realization of the method the pc is in */
359
360         code = *((codeinfo **) (pv + CodeinfoPointer));
361
362         /* search the line number table */
363
364         linenumber = dseg_get_linenumber_from_pc(&m, pv, pc);
365
366         /* now add a new entry to the staktrace */
367
368         stacktrace_add_entry(stb, m, linenumber);
369
370         return true;
371 }
372
373
374 /* stacktrace_create ***********************************************************
375
376    Generates a stacktrace from the thread passed into a
377    stacktracebuffer.  The stacktracebuffer is allocated on the
378    dump memory.
379    
380    NOTE: The first element in the stackframe chain must always be a
381          native stackframeinfo (e.g. VMThrowable.fillInStackTrace() is
382          a native function).
383
384    RETURN VALUE:
385       pointer to the stacktracebuffer, or
386       NULL if there is no stacktrace available for the
387       given thread.
388
389 *******************************************************************************/
390
391 stacktracebuffer *stacktrace_create(stackframeinfo *sfi)
392 {
393         stacktracebuffer *stb;
394         methodinfo       *m;
395         codeinfo         *code;
396         u1               *pv;
397         u1               *sp;
398         u4                framesize;
399         u1               *ra;
400         u1               *xpc;
401
402         /* prevent compiler warnings */
403
404         pv = NULL;
405         sp = NULL;
406         ra = NULL;
407
408         /* create a stacktracebuffer in dump memory */
409
410         stb = DNEW(stacktracebuffer);
411
412         stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
413         stb->used     = 0;
414         stb->entries  = DMNEW(stacktrace_entry, STACKTRACE_CAPACITY_DEFAULT);
415
416 #define PRINTMETHODS 0
417
418 #if PRINTMETHODS
419         printf("\n\nfillInStackTrace start:\n");
420         fflush(stdout);
421 #endif
422
423         /* Loop while we have a method pointer (asm_calljavafunction has
424            NULL) or there is a stackframeinfo in the chain. */
425
426         m = NULL;
427
428         while ((m != NULL) || (sfi != NULL)) {
429                 /* m == NULL should only happen for the first time and inline
430                    stackframe infos, like from the exception stubs or the
431                    patcher wrapper. */
432
433                 if (m == NULL) {
434                         /* for native stub stackframe infos, pv is always NULL */
435
436                         if (sfi->pv == NULL) {
437                                 /* get methodinfo, sp and ra from the current stackframe info */
438
439                                 m  = sfi->method;
440                                 sp = sfi->sp;           /* sp of parent Java function         */
441                                 ra = sfi->ra;
442
443                                 if (m)
444                                         stacktrace_add_entry(stb, m, 0);
445
446 #if PRINTMETHODS
447                                 printf("ra=%p sp=%p, ", ra, sp);
448                                 method_print(m);
449                                 printf(": native stub\n");
450                                 fflush(stdout);
451 #endif
452                                 /* This is an native stub stackframe info, so we can
453                                    get the parent pv from the return address
454                                    (ICMD_INVOKE*). */
455
456 #if defined(ENABLE_INTRP)
457                                 if (opt_intrp)
458                                         pv = codegen_get_pv_from_pc(ra);
459                                 else
460 #endif
461                                         {
462 #if defined(ENABLE_JIT)
463                                                 pv = md_codegen_get_pv_from_pc(ra);
464 #endif
465                                         }
466
467                                 /* get methodinfo pointer from parent data segment */
468
469                                 code = *((codeinfo **) (pv + CodeinfoPointer));
470
471                                 /* For asm_vm_call_method the codeinfo pointer is
472                                    NULL. */
473
474                                 m = (code == NULL) ? NULL : code->m;
475
476                         } else {
477                                 /* Inline stackframe infos are special: they have a
478                                    xpc of the actual exception position and the return
479                                    address saved since an inline stackframe info can
480                                    also be in a leaf method (no return address saved
481                                    on stack!!!).  ATTENTION: This one is also for
482                                    hardware exceptions!!! */
483
484                                 /* get methodinfo, sp and ra from the current stackframe info */
485
486                                 m   = sfi->method;      /* m == NULL                          */
487                                 pv  = sfi->pv;          /* pv of parent Java function         */
488                                 sp  = sfi->sp;          /* sp of parent Java function         */
489                                 ra  = sfi->ra;          /* ra of parent Java function         */
490                                 xpc = sfi->xpc;         /* actual exception position          */
491
492 #if PRINTMETHODS
493                                 printf("ra=%p sp=%p, ", ra, sp);
494                                 printf("NULL: inline stub\n");
495                                 fflush(stdout);
496 #endif
497
498                                 /* get methodinfo from current Java method */
499
500                                 code = *((codeinfo **) (pv + CodeinfoPointer));
501
502                                 /* For asm_vm_call_method the codeinfo pointer is
503                                    NULL. */
504
505                                 m = (code == NULL) ? NULL : code->m;
506
507                                 /* if m == NULL, this is a asm_calljavafunction call */
508
509                                 if (m != NULL) {
510 #if PRINTMETHODS
511                                         printf("ra=%p sp=%p, ", ra, sp);
512                                         method_print(m);
513                                         printf(": inline stub parent");
514                                         fflush(stdout);
515 #endif
516
517 #if defined(ENABLE_INTRP)
518                                         if (!opt_intrp) {
519 #endif
520
521                                         /* add the method to the stacktrace */
522
523                                         stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) xpc));
524
525                                         /* get the current stack frame size */
526
527                                         framesize = *((u4 *) (pv + FrameSize));
528
529 #if PRINTMETHODS
530                                         printf(", framesize=%d\n", framesize);
531                                         fflush(stdout);
532 #endif
533
534                                         /* Set stack pointer to stackframe of parent Java
535                                            function of the current Java function. */
536
537 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
538                                         sp += framesize + SIZEOF_VOID_P;
539 #elif defined(__SPARC_64__)
540                                         sp = md_get_framepointer(sp);
541 #else
542                                         sp += framesize;
543 #endif
544
545                                         /* get data segment and methodinfo pointer from
546                                            parent method */
547
548 #if defined(ENABLE_JIT)
549                                         pv = md_codegen_get_pv_from_pc(ra);
550 #endif
551
552                                         code = *((codeinfo **) (pv + CodeinfoPointer));
553
554                                         /* For asm_vm_call_method the codeinfo pointer is
555                                            NULL. */
556
557                                         m = (code == NULL) ? NULL : code->m;
558
559 #if defined(ENABLE_INTRP)
560                                         }
561 #endif
562                                 }
563 #if PRINTMETHODS
564                                 else {
565                                         printf("ra=%p sp=%p, ", ra, sp);
566                                         printf("asm_calljavafunction\n");
567                                         fflush(stdout);
568                                 }
569 #endif
570                         }
571
572                         /* get previous stackframeinfo in the chain */
573
574                         sfi = sfi->prev;
575
576                 } else {
577 #if PRINTMETHODS
578                         printf("ra=%p sp=%p, ", ra, sp);
579                         method_print(m);
580                         printf(": JIT");
581                         fflush(stdout);
582 #endif
583
584                         /* JIT method found, add it to the stacktrace (we subtract
585                            1 from the return address since it points the the
586                            instruction after call). */
587
588                         stacktrace_add_method(stb, m, pv, (u1 *) ((ptrint) ra) - 1);
589
590                         /* get the current stack frame size */
591
592                         framesize = *((u4 *) (pv + FrameSize));
593
594 #if PRINTMETHODS
595                         printf(", framesize=%d\n", framesize);
596                         fflush(stdout);
597 #endif
598
599                         /* get return address of current stack frame */
600
601 #if defined(ENABLE_JIT)
602 # if defined(ENABLE_INTRP)
603                         if (opt_intrp)
604                                 ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
605                         else
606 # endif
607                                 ra = md_stacktrace_get_returnaddress(sp, framesize);
608 #else
609                         ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
610 #endif
611
612                         /* get data segment and methodinfo pointer from parent method */
613
614 #if defined(ENABLE_INTRP)
615                         if (opt_intrp)
616                                 pv = codegen_get_pv_from_pc(ra);
617                         else
618 #endif
619                                 {
620 #if defined(ENABLE_JIT)
621 # if defined(__SPARC_64__)
622                                         sp = md_get_framepointer(sp);
623                                         pv = md_get_pv_from_stackframe(sp);
624 # else
625                                         pv = md_codegen_get_pv_from_pc(ra);
626 # endif
627 #endif
628                                 }
629
630                         code = *((codeinfo **) (pv + CodeinfoPointer));
631
632                         /* For asm_vm_call_method the codeinfo pointer is NULL. */
633
634                         m = (code == NULL) ? NULL : code->m;
635
636                         /* walk the stack */
637
638 #if defined(ENABLE_INTRP)
639                         if (opt_intrp)
640                                 sp = *(u1 **) (sp - framesize);
641                         else
642 #endif
643                                 {
644 #if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
645                                         sp += framesize + SIZEOF_VOID_P;
646 #elif defined(__SPARC_64__)
647                                         /* already has the new sp */
648 #else
649                                         sp += framesize;
650 #endif
651                                 }
652                 }
653         }
654
655         /* return the stacktracebuffer */
656
657         if (stb->used == 0)
658                 return NULL;
659         else
660                 return stb;
661 }
662
663
664 /* stacktrace_fillInStackTrace *************************************************
665
666    Generate a stacktrace from the current thread for
667    java.lang.VMThrowable.fillInStackTrace.
668
669 *******************************************************************************/
670
671 stacktracecontainer *stacktrace_fillInStackTrace(void)
672 {
673         stacktracebuffer    *stb;
674         stacktracecontainer *gcstc;
675         s4                   gcstc_size;
676         s4                   dumpsize;
677         CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
678
679         /* mark start of dump memory area */
680
681         dumpsize = dump_size();
682
683         /* create a stacktrace from the current thread */
684
685         stb = stacktrace_create(STACKFRAMEINFO);
686
687         if (stb == NULL)
688                 goto return_NULL;
689
690         /* allocate memory from the GC heap and copy the stacktrace buffer */
691         /* ATTENTION: use stacktracecontainer for this and make it look like
692        an array */
693
694         gcstc_size = sizeof(stacktracebuffer) +
695                      sizeof(stacktrace_entry) * stb->used;
696         gcstc = (stacktracecontainer *) builtin_newarray_byte(gcstc_size);
697
698         if (gcstc == NULL)
699                 goto return_NULL;
700
701         gcstc->stb.capacity = stb->capacity;
702         gcstc->stb.used     = stb->used;
703         gcstc->stb.entries  = gcstc->data;
704
705         MCOPY(gcstc->data, stb->entries, stacktrace_entry, stb->used);
706
707         /* release dump memory */
708
709         dump_release(dumpsize);
710
711         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
712                                                                    stacktrace_overhead)
713         return gcstc;
714
715 return_NULL:
716         dump_release(dumpsize);
717
718         CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
719                                                                    stacktrace_overhead)
720
721         return NULL;
722 }
723
724
725 /* stacktrace_getClassContext **************************************************
726
727    Creates a Class context array.
728
729    RETURN VALUE:
730       the array of java.lang.Class objects, or
731           NULL if an exception has been thrown
732
733 *******************************************************************************/
734
735 java_handle_objectarray_t *stacktrace_getClassContext(void)
736 {
737         stacktracebuffer          *stb;
738         stacktrace_entry          *ste;
739         java_handle_objectarray_t *oa;
740         s4                         oalength;
741         s4                         i;
742         s4                         dumpsize;
743         CYCLES_STATS_DECLARE_AND_START
744
745         /* mark start of dump memory area */
746
747         dumpsize = dump_size();
748
749         /* create a stacktrace for the current thread */
750
751         stb = stacktrace_create(STACKFRAMEINFO);
752
753         if (stb == NULL)
754                 goto return_NULL;
755
756         /* calculate the size of the Class array */
757
758         for (i = 0, oalength = 0; i < stb->used; i++)
759                 if (stb->entries[i].method != NULL)
760                         oalength++;
761
762         /* The first entry corresponds to the method whose implementation */
763         /* calls stacktrace_getClassContext. We remove that entry.        */
764
765         ste = &(stb->entries[0]);
766         ste++;
767         oalength--;
768
769         /* allocate the Class array */
770
771         oa = builtin_anewarray(oalength, class_java_lang_Class);
772         if (!oa)
773                 goto return_NULL;
774
775         /* fill the Class array from the stacktracebuffer */
776
777         for(i = 0; i < oalength; i++, ste++) {
778                 if (ste->method == NULL) {
779                         i--;
780                         continue;
781                 }
782
783                 oa->data[i] = (java_object_t *) ste->method->class;
784         }
785
786         /* release dump memory */
787
788         dump_release(dumpsize);
789
790         CYCLES_STATS_END(stacktrace_getClassContext)
791
792         return oa;
793
794 return_NULL:
795         dump_release(dumpsize);
796
797         CYCLES_STATS_END(stacktrace_getClassContext)
798
799         return NULL;
800 }
801
802
803 /* stacktrace_getCurrentClass **************************************************
804
805    Find the current class by walking the stack trace.
806
807    Quote from the JNI documentation:
808          
809    In the Java 2 Platform, FindClass locates the class loader
810    associated with the current native method.  If the native code
811    belongs to a system class, no class loader will be
812    involved. Otherwise, the proper class loader will be invoked to
813    load and link the named class. When FindClass is called through the
814    Invocation Interface, there is no current native method or its
815    associated class loader. In that case, the result of
816    ClassLoader.getBaseClassLoader is used."
817
818 *******************************************************************************/
819
820 #if defined(ENABLE_JAVASE)
821 classinfo *stacktrace_getCurrentClass(void)
822 {
823         stacktracebuffer  *stb;
824         stacktrace_entry  *ste;
825         methodinfo        *m;
826         s4                 i;
827         s4                 dumpsize;
828         CYCLES_STATS_DECLARE_AND_START
829
830         /* mark start of dump memory area */
831
832         dumpsize = dump_size();
833
834         /* create a stacktrace for the current thread */
835
836         stb = stacktrace_create(STACKFRAMEINFO);
837
838         if (stb == NULL)
839                 goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
840
841         /* iterate over all stacktrace entries and find the first suitable
842            class */
843
844         for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
845                 m = ste->method;
846
847                 if (m == NULL)
848                         continue;
849
850                 if (m->class == class_java_security_PrivilegedAction)
851                         goto return_NULL;
852
853                 if (m->class != NULL) {
854                         dump_release(dumpsize);
855
856                         CYCLES_STATS_END(stacktrace_getCurrentClass)
857
858                         return m->class;
859                 }
860         }
861
862         /* no Java method found on the stack */
863
864 return_NULL:
865         dump_release(dumpsize);
866
867         CYCLES_STATS_END(stacktrace_getCurrentClass)
868
869         return NULL;
870 }
871 #endif /* ENABLE_JAVASE */
872
873
874 /* stacktrace_getStack *********************************************************
875
876    Create a 2-dimensional array for java.security.VMAccessControler.
877
878    RETURN VALUE:
879       the arrary, or
880           NULL if an exception has been thrown
881
882 *******************************************************************************/
883
884 #if defined(ENABLE_JAVASE)
885 java_handle_objectarray_t *stacktrace_getStack(void)
886 {
887         stacktracebuffer          *stb;
888         stacktrace_entry          *ste;
889         java_handle_objectarray_t *oa;
890         java_handle_objectarray_t *classes;
891         java_handle_objectarray_t *methodnames;
892         classinfo                 *c;
893         java_handle_t             *string;
894         s4                         i;
895         s4                         dumpsize;
896         CYCLES_STATS_DECLARE_AND_START
897
898         /* mark start of dump memory area */
899
900         dumpsize = dump_size();
901
902         /* create a stacktrace for the current thread */
903
904         stb = stacktrace_create(STACKFRAMEINFO);
905
906         if (stb == NULL)
907                 goto return_NULL;
908
909         /* get the first stacktrace entry */
910
911         ste = &(stb->entries[0]);
912
913         /* allocate all required arrays */
914
915         oa = builtin_anewarray(2, arrayclass_java_lang_Object);
916
917         if (oa == NULL)
918                 goto return_NULL;
919
920         classes = builtin_anewarray(stb->used, class_java_lang_Class);
921
922         if (classes == NULL)
923                 goto return_NULL;
924
925         methodnames = builtin_anewarray(stb->used, class_java_lang_String);
926
927         if (methodnames == NULL)
928                 goto return_NULL;
929
930         /* set up the 2-dimensional array */
931
932         oa->data[0] = (java_object_t *) classes;
933         oa->data[1] = (java_object_t *) methodnames;
934
935         /* iterate over all stacktrace entries */
936
937         for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
938                 c = ste->method->class;
939
940                 classes->data[i] = (java_object_t *) c;
941
942                 string = javastring_new(ste->method->name);
943
944                 if (string == NULL)
945                         goto return_NULL;
946
947                 methodnames->data[i] = string;
948         }
949
950         /* return the 2-dimensional array */
951
952         dump_release(dumpsize);
953
954         CYCLES_STATS_END(stacktrace_getStack)
955
956         return oa;
957
958 return_NULL:
959         dump_release(dumpsize);
960
961         CYCLES_STATS_END(stacktrace_getStack)
962
963         return NULL;
964 }
965 #endif /* ENABLE_JAVASE */
966
967
968 /* stacktrace_print_trace_from_buffer ******************************************
969
970    Print the stacktrace of a given stacktracebuffer with CACAO intern
971    methods (no Java help). This method is used by
972    stacktrace_dump_trace and builtin_trace_exception.
973
974 *******************************************************************************/
975
976 void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
977 {
978         stacktrace_entry *ste;
979         methodinfo       *m;
980         s4                i;
981
982         ste = &(stb->entries[0]);
983
984         for (i = 0; i < stb->used; i++, ste++) {
985                 m = ste->method;
986
987                 printf("\tat ");
988                 utf_display_printable_ascii_classname(m->class->name);
989                 printf(".");
990                 utf_display_printable_ascii(m->name);
991                 utf_display_printable_ascii(m->descriptor);
992
993                 if (m->flags & ACC_NATIVE) {
994                         puts("(Native Method)");
995
996                 } else {
997                         printf("(");
998                         utf_display_printable_ascii(m->class->sourcefile);
999                         printf(":%d)\n", (u4) ste->linenumber);
1000                 }
1001         }
1002
1003         /* just to be sure */
1004
1005         fflush(stdout);
1006 }
1007
1008
1009 /* stacktrace_print_trace ******************************************************
1010
1011    Print the stacktrace of a given exception. More or less a wrapper
1012    to stacktrace_print_trace_from_buffer.
1013
1014 *******************************************************************************/
1015
1016 void stacktrace_print_trace(java_handle_t *xptr)
1017 {
1018         java_lang_Throwable   *t;
1019 #if defined(WITH_CLASSPATH_GNU)
1020         java_lang_VMThrowable *vmt;
1021 #endif
1022         stacktracecontainer   *stc;
1023         stacktracebuffer      *stb;
1024
1025         t = (java_lang_Throwable *) xptr;
1026
1027         if (t == NULL)
1028                 return;
1029
1030         /* now print the stacktrace */
1031
1032 #if defined(WITH_CLASSPATH_GNU)
1033         LLNI_field_get_ref(t, vmState, vmt);
1034         stc = (stacktracecontainer *) LLNI_field_direct(vmt, vmData);
1035 #elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
1036         stc = (stacktracecontainer *) t->backtrace;
1037 #else
1038 # error unknown classpath configuration
1039 #endif
1040
1041         stb = &(stc->stb);
1042
1043         stacktrace_print_trace_from_buffer(stb);
1044 }
1045
1046
1047 #if defined(ENABLE_CYCLES_STATS)
1048 void stacktrace_print_cycles_stats(FILE *file)
1049 {
1050         CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
1051         CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
1052         CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
1053         CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
1054         CYCLES_STATS_PRINT(stacktrace_getStack        ,file);
1055 }
1056 #endif
1057
1058
1059 /*
1060  * These are local overrides for various environment variables in Emacs.
1061  * Please do not remove this and leave it at the end of the file, where
1062  * Emacs will automagically detect them.
1063  * ---------------------------------------------------------------------
1064  * Local variables:
1065  * mode: c
1066  * indent-tabs-mode: t
1067  * c-basic-offset: 4
1068  * tab-width: 4
1069  * End:
1070  * vim:noexpandtab:sw=4:ts=4:
1071  */