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