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