* src/threads/thread.c: Moved to .cpp.
[cacao.git] / src / vm / jit / trace.cpp
1 /* src/vm/jit/trace.cpp - Functions for tracing from java code.
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 // FIXME For now we export everything as C functions.
27 extern "C" {
28
29 #include "config.h"
30
31 #include <stdio.h>
32
33 #include "arch.h"
34 #include "md-abi.h"
35
36 #include "mm/memory.h"
37
38 #include "native/jni.h"
39 #include "native/llni.h"
40
41 #include "native/include/java_lang_String.h"
42 #include "native/include/java_lang_Throwable.h"
43
44 #include "threads/thread.hpp"
45
46 #include "toolbox/logging.h"
47
48 #include "vm/global.h"
49 #include "vm/stringlocal.h"
50 #include "vm/jit/argument.h"
51 #include "vm/jit/codegen-common.h"
52 #include "vm/jit/trace.hpp"
53 #include "vm/jit/show.h"
54
55 #include "vmcore/globals.hpp"
56 #include "vmcore/options.h"
57 #include "vmcore/utf8.h"
58
59
60 #if !defined(NDEBUG)
61
62
63 /* global variables ***********************************************************/
64
65 #if !defined(ENABLE_THREADS)
66 s4 _no_threads_tracejavacallindent = 0;
67 u4 _no_threads_tracejavacallcount= 0;
68 #endif
69
70
71 /* trace_java_call_print_argument **********************************************
72
73    XXX: Document me!
74
75 *******************************************************************************/
76
77 static char *trace_java_call_print_argument(methodinfo *m, char *logtext, s4 *logtextlen, typedesc *paramtype, imm_union imu)
78 {
79         java_object_t *o;
80         classinfo     *c;
81         utf           *u;
82         u4             len;
83
84         switch (paramtype->type) {
85         case TYPE_INT:
86                 sprintf(logtext + strlen(logtext), "%d (0x%08x)", (int32_t)imu.l, (int32_t)imu.l);
87                 break;
88
89         case TYPE_LNG:
90 #if SIZEOF_VOID_P == 4
91                 sprintf(logtext + strlen(logtext), "%lld (0x%016llx)", imu.l, imu.l);
92 #else
93                 sprintf(logtext + strlen(logtext), "%ld (0x%016lx)", imu.l, imu.l);
94 #endif
95                 break;
96
97         case TYPE_FLT:
98                 sprintf(logtext + strlen(logtext), "%g (0x%08x)", imu.f, imu.i);
99                 break;
100
101         case TYPE_DBL:
102 #if SIZEOF_VOID_P == 4
103                 sprintf(logtext + strlen(logtext), "%g (0x%016llx)", imu.d, imu.l);
104 #else
105                 sprintf(logtext + strlen(logtext), "%g (0x%016lx)", imu.d, imu.l);
106 #endif
107                 break;
108
109         case TYPE_ADR:
110 #if SIZEOF_VOID_P == 4
111                 sprintf(logtext + strlen(logtext), "0x%08x", (ptrint) imu.l);
112 #else
113                 sprintf(logtext + strlen(logtext), "0x%016lx", (ptrint) imu.l);
114 #endif
115
116                 /* Workaround for sun.misc.Unsafe methods.  In the future
117                    (exact GC) we should check if the address is on the GC
118                    heap. */
119
120                 if ((m->clazz       != NULL) &&
121                         (m->clazz->name == utf_new_char("sun/misc/Unsafe")))
122                         break;
123
124                 /* Cast to java.lang.Object. */
125
126                 o = (java_object_t *) (ptrint) imu.l;
127
128                 /* Check return argument for java.lang.Class or
129                    java.lang.String. */
130
131                 if (o != NULL) {
132                         if (o->vftbl->clazz == class_java_lang_String) {
133                                 /* get java.lang.String object and the length of the
134                                    string */
135
136                                 u = javastring_toutf(o, false);
137
138                                 len = strlen(" (String = \"") + utf_bytes(u) + strlen("\")");
139
140                                 /* realloc memory for string length */
141
142                                 logtext = DMREALLOC(logtext, char, *logtextlen, *logtextlen + len);
143                                 *logtextlen += len;
144
145                                 /* convert to utf8 string and strcat it to the logtext */
146
147                                 strcat(logtext, " (String = \"");
148                                 utf_cat(logtext, u);
149                                 strcat(logtext, "\")");
150                         }
151                         else {
152                                 if (o->vftbl->clazz == class_java_lang_Class) {
153                                         /* if the object returned is a java.lang.Class
154                                            cast it to classinfo structure and get the name
155                                            of the class */
156
157                                         c = (classinfo *) o;
158
159                                         u = c->name;
160                                 }
161                                 else {
162                                         /* if the object returned is not a java.lang.String or
163                                            a java.lang.Class just print the name of the class */
164
165                                         u = o->vftbl->clazz->name;
166                                 }
167
168                                 len = strlen(" (Class = \"") + utf_bytes(u) + strlen("\")");
169
170                                 /* realloc memory for string length */
171
172                                 logtext = DMREALLOC(logtext, char, *logtextlen, *logtextlen + len);
173                                 *logtextlen += len;
174
175                                 /* strcat to the logtext */
176
177                                 strcat(logtext, " (Class = \"");
178                                 utf_cat_classname(logtext, u);
179                                 strcat(logtext, "\")");
180                         }
181                 }
182         }
183
184         return logtext;
185 }
186
187 /* trace_java_call_enter ******************************************************
188  
189    Traces an entry into a java method.
190
191    arg_regs: Array containing all argument registers as int64_t values in
192    the same order as listed in m->methoddesc. The array is usually allocated
193    on the stack and used for restoring the argument registers later.
194
195    stack: Pointer to first on stack argument in the same format passed to 
196    asm_vm_call_method.
197
198 *******************************************************************************/
199
200 void trace_java_call_enter(methodinfo *m, uint64_t *arg_regs, uint64_t *stack)
201 {
202         methoddesc *md;
203         imm_union   arg;
204         char       *logtext;
205         s4          logtextlen;
206         s4          i;
207         s4          pos;
208         int32_t     dumpmarker;
209
210         /* We don't trace builtin functions here because the argument
211            passing happens via the native ABI and does not fit these
212            functions. */
213
214         if (method_is_builtin(m))
215                 return;
216
217 #if defined(ENABLE_DEBUG_FILTER)
218         if (!show_filters_test_verbosecall_enter(m))
219                 return;
220 #endif
221
222 #if defined(ENABLE_VMLOG)
223         vmlog_cacao_enter_method(m);
224         return;
225 #endif
226
227         md = m->parseddesc;
228
229         /* calculate message length */
230
231         logtextlen =
232                 strlen("4294967295 ") +
233                 strlen("-2147483647-") +        /* INT_MAX should be sufficient       */
234                 TRACEJAVACALLINDENT +
235                 strlen("called: ") +
236                 ((m->clazz == NULL) ? strlen("NULL") : utf_bytes(m->clazz->name)) +
237                 strlen(".") +
238                 utf_bytes(m->name) +
239                 utf_bytes(m->descriptor);
240
241         /* Actually it's not possible to have all flags printed, but:
242            safety first! */
243
244         logtextlen +=
245                 strlen(" PUBLIC") +
246                 strlen(" PRIVATE") +
247                 strlen(" PROTECTED") +
248                 strlen(" STATIC") +
249                 strlen(" FINAL") +
250                 strlen(" SYNCHRONIZED") +
251                 strlen(" VOLATILE") +
252                 strlen(" TRANSIENT") +
253                 strlen(" NATIVE") +
254                 strlen(" INTERFACE") +
255                 strlen(" ABSTRACT") +
256                 strlen(" METHOD_BUILTIN");
257
258         /* add maximal argument length */
259
260         logtextlen +=
261                 strlen("(") +
262                 strlen("-9223372036854775808 (0x123456789abcdef0), ") * md->paramcount +
263                 strlen("...(255)") +
264                 strlen(")");
265
266         /* allocate memory */
267
268         DMARKER;
269
270         logtext = DMNEW(char, logtextlen);
271
272         TRACEJAVACALLCOUNT++;
273
274         sprintf(logtext, "%10d ", TRACEJAVACALLCOUNT);
275         sprintf(logtext + strlen(logtext), "-%d-", TRACEJAVACALLINDENT);
276
277         pos = strlen(logtext);
278
279         for (i = 0; i < TRACEJAVACALLINDENT; i++)
280                 logtext[pos++] = '\t';
281
282         strcpy(logtext + pos, "called: ");
283
284         if (m->clazz != NULL)
285                 utf_cat_classname(logtext, m->clazz->name);
286         else
287                 strcat(logtext, "NULL");
288         strcat(logtext, ".");
289         utf_cat(logtext, m->name);
290         utf_cat(logtext, m->descriptor);
291
292         if (m->flags & ACC_PUBLIC)         strcat(logtext, " PUBLIC");
293         if (m->flags & ACC_PRIVATE)        strcat(logtext, " PRIVATE");
294         if (m->flags & ACC_PROTECTED)      strcat(logtext, " PROTECTED");
295         if (m->flags & ACC_STATIC)         strcat(logtext, " STATIC");
296         if (m->flags & ACC_FINAL)          strcat(logtext, " FINAL");
297         if (m->flags & ACC_SYNCHRONIZED)   strcat(logtext, " SYNCHRONIZED");
298         if (m->flags & ACC_VOLATILE)       strcat(logtext, " VOLATILE");
299         if (m->flags & ACC_TRANSIENT)      strcat(logtext, " TRANSIENT");
300         if (m->flags & ACC_NATIVE)         strcat(logtext, " NATIVE");
301         if (m->flags & ACC_INTERFACE)      strcat(logtext, " INTERFACE");
302         if (m->flags & ACC_ABSTRACT)       strcat(logtext, " ABSTRACT");
303
304         strcat(logtext, "(");
305
306         for (i = 0; i < md->paramcount; ++i) {
307                 arg = argument_jitarray_load(md, i, arg_regs, stack);
308                 logtext = trace_java_call_print_argument(m, logtext, &logtextlen,
309                                                                                                  &md->paramtypes[i], arg);
310                 if (i != (md->paramcount - 1)) {
311                         strcat(logtext, ", ");
312                 }
313         }
314
315         strcat(logtext, ")");
316
317         log_text(logtext);
318
319         /* release memory */
320
321         DRELEASE;
322
323         TRACEJAVACALLINDENT++;
324
325 }
326
327 /* trace_java_call_exit ********************************************************
328
329    Traces an exit form a java method.
330
331    return_regs: Array of size 1 containing return register.
332    The array is usually allocated on the stack and used for restoring the
333    registers later.
334
335 *******************************************************************************/
336
337 void trace_java_call_exit(methodinfo *m, uint64_t *return_regs)
338 {
339         methoddesc *md;
340         char       *logtext;
341         s4          logtextlen;
342         s4          i;
343         s4          pos;
344         imm_union   val;
345         int32_t     dumpmarker;
346
347         /* We don't trace builtin functions here because the argument
348            passing happens via the native ABI and does not fit these
349            functions. */
350
351         if (method_is_builtin(m))
352                 return;
353
354 #if defined(ENABLE_DEBUG_FILTER)
355         if (!show_filters_test_verbosecall_exit(m))
356                 return;
357 #endif
358
359 #if defined(ENABLE_VMLOG)
360         vmlog_cacao_leave_method(m);
361         return;
362 #endif
363
364         md = m->parseddesc;
365
366         /* outdent the log message */
367
368         if (TRACEJAVACALLINDENT)
369                 TRACEJAVACALLINDENT--;
370         else
371                 log_text("trace_java_call_exit: WARNING: unmatched unindent");
372
373         /* calculate message length */
374
375         logtextlen =
376                 strlen("4294967295 ") +
377                 strlen("-2147483647-") +        /* INT_MAX should be sufficient       */
378                 TRACEJAVACALLINDENT +
379                 strlen("finished: ") +
380                 ((m->clazz == NULL) ? strlen("NULL") : utf_bytes(m->clazz->name)) +
381                 strlen(".") +
382                 utf_bytes(m->name) +
383                 utf_bytes(m->descriptor) +
384                 strlen(" SYNCHRONIZED") + strlen("(") + strlen(")");
385
386         /* add maximal argument length */
387
388         logtextlen += strlen("->0.4872328470301428 (0x0123456789abcdef)");
389
390         /* allocate memory */
391
392         DMARKER;
393
394         logtext = DMNEW(char, logtextlen);
395
396         /* generate the message */
397
398         sprintf(logtext, "           ");
399         sprintf(logtext + strlen(logtext), "-%d-", TRACEJAVACALLINDENT);
400
401         pos = strlen(logtext);
402
403         for (i = 0; i < TRACEJAVACALLINDENT; i++)
404                 logtext[pos++] = '\t';
405
406         strcpy(logtext + pos, "finished: ");
407         if (m->clazz != NULL)
408                 utf_cat_classname(logtext, m->clazz->name);
409         else
410                 strcat(logtext, "NULL");
411         strcat(logtext, ".");
412         utf_cat(logtext, m->name);
413         utf_cat(logtext, m->descriptor);
414
415         if (!IS_VOID_TYPE(md->returntype.type)) {
416                 strcat(logtext, "->");
417                 val = argument_jitreturn_load(md, return_regs);
418
419                 logtext =
420                         trace_java_call_print_argument(m, logtext, &logtextlen,
421                                                                                    &md->returntype, val);
422         }
423
424         log_text(logtext);
425
426         /* release memory */
427
428         DRELEASE;
429 }
430
431
432 /* trace_exception *************************************************************
433
434    Traces an exception which is handled by exceptions_handle_exception.
435
436 *******************************************************************************/
437
438 void trace_exception(java_object_t *xptr, methodinfo *m, void *pos)
439 {
440         char *logtext;
441         s4    logtextlen;
442         codeinfo *code;
443         int32_t   dumpmarker;
444
445         /* calculate message length */
446
447         if (xptr) {
448                 logtextlen =
449                         strlen("Exception ") + utf_bytes(xptr->vftbl->clazz->name);
450         } 
451         else {
452                 logtextlen = strlen("Some Throwable");
453         }
454
455         logtextlen += strlen(" thrown in ");
456
457         if (m) {
458                 logtextlen +=
459                         utf_bytes(m->clazz->name) +
460                         strlen(".") +
461                         utf_bytes(m->name) +
462                         utf_bytes(m->descriptor) +
463                         strlen("(NOSYNC,NATIVE");
464
465 #if SIZEOF_VOID_P == 8
466                 logtextlen +=
467                         strlen(")(0x123456789abcdef0) at position 0x123456789abcdef0 (");
468 #else
469                 logtextlen += strlen(")(0x12345678) at position 0x12345678 (");
470 #endif
471
472                 if (m->clazz->sourcefile == NULL)
473                         logtextlen += strlen("<NO CLASSFILE INFORMATION>");
474                 else
475                         logtextlen += utf_bytes(m->clazz->sourcefile);
476
477                 logtextlen += strlen(":65536)");
478
479         } 
480         else {
481                 logtextlen += strlen("call_java_method");
482         }
483
484         logtextlen += strlen("0");
485
486         /* allocate memory */
487
488         DMARKER;
489
490         logtext = DMNEW(char, logtextlen);
491
492         if (xptr) {
493                 strcpy(logtext, "Exception ");
494                 utf_cat_classname(logtext, xptr->vftbl->clazz->name);
495
496         } else {
497                 strcpy(logtext, "Some Throwable");
498         }
499
500         strcat(logtext, " thrown in ");
501
502         if (m) {
503                 utf_cat_classname(logtext, m->clazz->name);
504                 strcat(logtext, ".");
505                 utf_cat(logtext, m->name);
506                 utf_cat(logtext, m->descriptor);
507
508                 if (m->flags & ACC_SYNCHRONIZED)
509                         strcat(logtext, "(SYNC");
510                 else
511                         strcat(logtext, "(NOSYNC");
512
513                 if (m->flags & ACC_NATIVE) {
514                         strcat(logtext, ",NATIVE");
515
516                         code = m->code;
517
518 #if SIZEOF_VOID_P == 8
519                         sprintf(logtext + strlen(logtext),
520                                         ")(0x%016lx) at position 0x%016lx",
521                                         (ptrint) code->entrypoint, (ptrint) pos);
522 #else
523                         sprintf(logtext + strlen(logtext),
524                                         ")(0x%08x) at position 0x%08x",
525                                         (ptrint) code->entrypoint, (ptrint) pos);
526 #endif
527
528                 } else {
529
530                         /* XXX preliminary: This should get the actual codeinfo */
531                         /* in which the exception happened.                     */
532                         code = m->code;
533                         
534 #if SIZEOF_VOID_P == 8
535                         sprintf(logtext + strlen(logtext),
536                                         ")(0x%016lx) at position 0x%016lx (",
537                                         (ptrint) code->entrypoint, (ptrint) pos);
538 #else
539                         sprintf(logtext + strlen(logtext),
540                                         ")(0x%08x) at position 0x%08x (",
541                                         (ptrint) code->entrypoint, (ptrint) pos);
542 #endif
543
544                         if (m->clazz->sourcefile == NULL)
545                                 strcat(logtext, "<NO CLASSFILE INFORMATION>");
546                         else
547                                 utf_cat(logtext, m->clazz->sourcefile);
548
549                         sprintf(logtext + strlen(logtext), ":%d)", 0);
550                 }
551
552         } else
553                 strcat(logtext, "call_java_method");
554
555         log_text(logtext);
556
557         /* release memory */
558
559         DRELEASE;
560 }
561
562
563 /* trace_exception_builtin *****************************************************
564
565    Traces an exception which is thrown by builtin_throw_exception.
566
567 *******************************************************************************/
568
569 void trace_exception_builtin(java_object_t *xptr)
570 {
571         java_lang_Throwable *t;
572         java_lang_String    *s;
573         char                *logtext;
574         s4                   logtextlen;
575         int32_t              dumpmarker;
576
577         t = (java_lang_Throwable *) xptr;
578
579         /* get detail message */
580         if (t)
581                 LLNI_field_get_ref(t, detailMessage, s);
582
583         /* calculate message length */
584
585         logtextlen = strlen("Builtin exception thrown: ") + strlen("0");
586
587         if (t) {
588                 logtextlen +=
589                         utf_bytes(xptr->vftbl->clazz->name);
590                 if (s) {
591                         logtextlen += strlen(": ") +
592                                 u2_utflength(LLNI_field_direct(s, value)->data 
593                                                                 + LLNI_field_direct(s, offset),
594                                                          LLNI_field_direct(s,count));
595                 }
596         } 
597         else {
598                 logtextlen += strlen("(nil)");
599         }
600
601         /* allocate memory */
602
603         DMARKER;
604
605         logtext = DMNEW(char, logtextlen);
606
607         strcpy(logtext, "Builtin exception thrown: ");
608
609         if (t) {
610                 utf_cat_classname(logtext, xptr->vftbl->clazz->name);
611
612                 if (s) {
613                         char *buf;
614
615                         buf = javastring_tochar((java_handle_t *) s);
616                         strcat(logtext, ": ");
617                         strcat(logtext, buf);
618                         MFREE(buf, char, strlen(buf) + 1);
619                 }
620
621         } else {
622                 strcat(logtext, "(nil)");
623         }
624
625         log_text(logtext);
626
627         /* release memory */
628
629         DRELEASE;
630 }
631
632 #endif /* !defined(NDEBUG) */
633
634 } // extern "C"
635
636
637 /*
638  * These are local overrides for various environment variables in Emacs.
639  * Please do not remove this and leave it at the end of the file, where
640  * Emacs will automagically detect them.
641  * ---------------------------------------------------------------------
642  * Local variables:
643  * mode: c++
644  * indent-tabs-mode: t
645  * c-basic-offset: 4
646  * tab-width: 4
647  * End:
648  * vim:noexpandtab:sw=4:ts=4:
649  */