f6dd77abae0d6f6d036637b0940cdd7beefb8adc
[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.hpp"
34
35 #include "native/llni.h"
36
37 #include "threads/thread.hpp"
38
39 #include "toolbox/logging.hpp"
40
41 #include "vm/array.hpp"
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.hpp"
50 #include "vm/jit/codegen-common.hpp"
51 #include "vm/jit/trace.hpp"
52 #include "vm/jit/show.hpp"
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_handle_t*) (uintptr_t) 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 = (char*) DumpMemory::reallocate(logtext, *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 = (char*) DumpMemory::reallocate(logtext, *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
206         /* We don't trace builtin functions here because the argument
207            passing happens via the native ABI and does not fit these
208            functions. */
209
210         if (method_is_builtin(m))
211                 return;
212
213 #if defined(ENABLE_DEBUG_FILTER)
214         if (!show_filters_test_verbosecall_enter(m))
215                 return;
216 #endif
217
218 #if defined(ENABLE_VMLOG)
219         vmlog_cacao_enter_method(m);
220         return;
221 #endif
222
223         md = m->parseddesc;
224
225         /* calculate message length */
226
227         logtextlen =
228                 strlen("4294967295 ") +
229                 strlen("-2147483647-") +        /* INT_MAX should be sufficient       */
230                 TRACEJAVACALLINDENT +
231                 strlen("called: ") +
232                 ((m->clazz == NULL) ? strlen("NULL") : utf_bytes(m->clazz->name)) +
233                 strlen(".") +
234                 utf_bytes(m->name) +
235                 utf_bytes(m->descriptor);
236
237         /* Actually it's not possible to have all flags printed, but:
238            safety first! */
239
240         logtextlen +=
241                 strlen(" PUBLIC") +
242                 strlen(" PRIVATE") +
243                 strlen(" PROTECTED") +
244                 strlen(" STATIC") +
245                 strlen(" FINAL") +
246                 strlen(" SYNCHRONIZED") +
247                 strlen(" VOLATILE") +
248                 strlen(" TRANSIENT") +
249                 strlen(" NATIVE") +
250                 strlen(" INTERFACE") +
251                 strlen(" ABSTRACT") +
252                 strlen(" METHOD_BUILTIN");
253
254         /* add maximal argument length */
255
256         logtextlen +=
257                 strlen("(") +
258                 strlen("-9223372036854775808 (0x123456789abcdef0), ") * md->paramcount +
259                 strlen("...(255)") +
260                 strlen(")");
261
262         // Create new dump memory area.
263         DumpMemoryArea dma;
264
265         // TODO Use a std::string here.
266         logtext = (char*) DumpMemory::allocate(sizeof(char) * logtextlen);
267
268         TRACEJAVACALLCOUNT++;
269
270         sprintf(logtext, "%10d ", TRACEJAVACALLCOUNT);
271         sprintf(logtext + strlen(logtext), "-%d-", TRACEJAVACALLINDENT);
272
273         pos = strlen(logtext);
274
275         for (i = 0; i < TRACEJAVACALLINDENT; i++)
276                 logtext[pos++] = '\t';
277
278         strcpy(logtext + pos, "called: ");
279
280         if (m->clazz != NULL)
281                 utf_cat_classname(logtext, m->clazz->name);
282         else
283                 strcat(logtext, "NULL");
284         strcat(logtext, ".");
285         utf_cat(logtext, m->name);
286         utf_cat(logtext, m->descriptor);
287
288         if (m->flags & ACC_PUBLIC)         strcat(logtext, " PUBLIC");
289         if (m->flags & ACC_PRIVATE)        strcat(logtext, " PRIVATE");
290         if (m->flags & ACC_PROTECTED)      strcat(logtext, " PROTECTED");
291         if (m->flags & ACC_STATIC)         strcat(logtext, " STATIC");
292         if (m->flags & ACC_FINAL)          strcat(logtext, " FINAL");
293         if (m->flags & ACC_SYNCHRONIZED)   strcat(logtext, " SYNCHRONIZED");
294         if (m->flags & ACC_VOLATILE)       strcat(logtext, " VOLATILE");
295         if (m->flags & ACC_TRANSIENT)      strcat(logtext, " TRANSIENT");
296         if (m->flags & ACC_NATIVE)         strcat(logtext, " NATIVE");
297         if (m->flags & ACC_INTERFACE)      strcat(logtext, " INTERFACE");
298         if (m->flags & ACC_ABSTRACT)       strcat(logtext, " ABSTRACT");
299
300         strcat(logtext, "(");
301
302         for (i = 0; i < md->paramcount; ++i) {
303                 arg = argument_jitarray_load(md, i, arg_regs, stack);
304                 logtext = trace_java_call_print_argument(m, logtext, &logtextlen,
305                                                                                                  &md->paramtypes[i], arg);
306                 if (i != (md->paramcount - 1)) {
307                         strcat(logtext, ", ");
308                 }
309         }
310
311         strcat(logtext, ")");
312
313         log_text(logtext);
314
315         TRACEJAVACALLINDENT++;
316 }
317
318 /* trace_java_call_exit ********************************************************
319
320    Traces an exit form a java method.
321
322    return_regs: Array of size 1 containing return register.
323    The array is usually allocated on the stack and used for restoring the
324    registers later.
325
326 *******************************************************************************/
327
328 void trace_java_call_exit(methodinfo *m, uint64_t *return_regs)
329 {
330         methoddesc *md;
331         char       *logtext;
332         s4          logtextlen;
333         s4          i;
334         s4          pos;
335         imm_union   val;
336
337         /* We don't trace builtin functions here because the argument
338            passing happens via the native ABI and does not fit these
339            functions. */
340
341         if (method_is_builtin(m))
342                 return;
343
344 #if defined(ENABLE_DEBUG_FILTER)
345         if (!show_filters_test_verbosecall_exit(m))
346                 return;
347 #endif
348
349 #if defined(ENABLE_VMLOG)
350         vmlog_cacao_leave_method(m);
351         return;
352 #endif
353
354         md = m->parseddesc;
355
356         /* outdent the log message */
357
358         if (TRACEJAVACALLINDENT)
359                 TRACEJAVACALLINDENT--;
360         else
361                 log_text("trace_java_call_exit: WARNING: unmatched unindent");
362
363         /* calculate message length */
364
365         logtextlen =
366                 strlen("4294967295 ") +
367                 strlen("-2147483647-") +        /* INT_MAX should be sufficient       */
368                 TRACEJAVACALLINDENT +
369                 strlen("finished: ") +
370                 ((m->clazz == NULL) ? strlen("NULL") : utf_bytes(m->clazz->name)) +
371                 strlen(".") +
372                 utf_bytes(m->name) +
373                 utf_bytes(m->descriptor) +
374                 strlen(" SYNCHRONIZED") + strlen("(") + strlen(")");
375
376         /* add maximal argument length */
377
378         logtextlen += strlen("->0.4872328470301428 (0x0123456789abcdef)");
379
380         // Create new dump memory area.
381         DumpMemoryArea dma;
382
383         // TODO Use a std::string here.
384         logtext = (char*) DumpMemory::allocate(sizeof(char) * logtextlen);
385
386         /* generate the message */
387
388         sprintf(logtext, "           ");
389         sprintf(logtext + strlen(logtext), "-%d-", TRACEJAVACALLINDENT);
390
391         pos = strlen(logtext);
392
393         for (i = 0; i < TRACEJAVACALLINDENT; i++)
394                 logtext[pos++] = '\t';
395
396         strcpy(logtext + pos, "finished: ");
397         if (m->clazz != NULL)
398                 utf_cat_classname(logtext, m->clazz->name);
399         else
400                 strcat(logtext, "NULL");
401         strcat(logtext, ".");
402         utf_cat(logtext, m->name);
403         utf_cat(logtext, m->descriptor);
404
405         if (!IS_VOID_TYPE(md->returntype.type)) {
406                 strcat(logtext, "->");
407                 val = argument_jitreturn_load(md, return_regs);
408
409                 logtext =
410                         trace_java_call_print_argument(m, logtext, &logtextlen,
411                                                                                    &md->returntype, val);
412         }
413
414         log_text(logtext);
415 }
416
417
418 /* trace_exception *************************************************************
419
420    Traces an exception which is handled by exceptions_handle_exception.
421
422 *******************************************************************************/
423
424 void trace_exception(java_object_t *xptr, methodinfo *m, void *pos)
425 {
426         char *logtext;
427         s4    logtextlen;
428         codeinfo *code;
429
430         /* calculate message length */
431
432         if (xptr) {
433                 logtextlen =
434                         strlen("Exception ") + utf_bytes(xptr->vftbl->clazz->name);
435         } 
436         else {
437                 logtextlen = strlen("Some Throwable");
438         }
439
440         logtextlen += strlen(" thrown in ");
441
442         if (m) {
443                 logtextlen +=
444                         utf_bytes(m->clazz->name) +
445                         strlen(".") +
446                         utf_bytes(m->name) +
447                         utf_bytes(m->descriptor) +
448                         strlen("(NOSYNC,NATIVE");
449
450 #if SIZEOF_VOID_P == 8
451                 logtextlen +=
452                         strlen(")(0x123456789abcdef0) at position 0x123456789abcdef0 (");
453 #else
454                 logtextlen += strlen(")(0x12345678) at position 0x12345678 (");
455 #endif
456
457                 if (m->clazz->sourcefile == NULL)
458                         logtextlen += strlen("<NO CLASSFILE INFORMATION>");
459                 else
460                         logtextlen += utf_bytes(m->clazz->sourcefile);
461
462                 logtextlen += strlen(":65536)");
463
464         } 
465         else {
466                 logtextlen += strlen("call_java_method");
467         }
468
469         logtextlen += strlen("0");
470
471         // Create new dump memory area.
472         DumpMemoryArea dma;
473
474         // TODO Use a std::string here.
475         logtext = (char*) DumpMemory::allocate(sizeof(char) * logtextlen);
476
477         if (xptr) {
478                 strcpy(logtext, "Exception ");
479                 utf_cat_classname(logtext, xptr->vftbl->clazz->name);
480
481         } else {
482                 strcpy(logtext, "Some Throwable");
483         }
484
485         strcat(logtext, " thrown in ");
486
487         if (m) {
488                 utf_cat_classname(logtext, m->clazz->name);
489                 strcat(logtext, ".");
490                 utf_cat(logtext, m->name);
491                 utf_cat(logtext, m->descriptor);
492
493                 if (m->flags & ACC_SYNCHRONIZED)
494                         strcat(logtext, "(SYNC");
495                 else
496                         strcat(logtext, "(NOSYNC");
497
498                 if (m->flags & ACC_NATIVE) {
499                         strcat(logtext, ",NATIVE");
500
501                         code = m->code;
502
503 #if SIZEOF_VOID_P == 8
504                         sprintf(logtext + strlen(logtext),
505                                         ")(0x%016lx) at position 0x%016lx",
506                                         (ptrint) code->entrypoint, (ptrint) pos);
507 #else
508                         sprintf(logtext + strlen(logtext),
509                                         ")(0x%08x) at position 0x%08x",
510                                         (ptrint) code->entrypoint, (ptrint) pos);
511 #endif
512
513                 } else {
514
515                         /* XXX preliminary: This should get the actual codeinfo */
516                         /* in which the exception happened.                     */
517                         code = m->code;
518                         
519 #if SIZEOF_VOID_P == 8
520                         sprintf(logtext + strlen(logtext),
521                                         ")(0x%016lx) at position 0x%016lx (",
522                                         (ptrint) code->entrypoint, (ptrint) pos);
523 #else
524                         sprintf(logtext + strlen(logtext),
525                                         ")(0x%08x) at position 0x%08x (",
526                                         (ptrint) code->entrypoint, (ptrint) pos);
527 #endif
528
529                         if (m->clazz->sourcefile == NULL)
530                                 strcat(logtext, "<NO CLASSFILE INFORMATION>");
531                         else
532                                 utf_cat(logtext, m->clazz->sourcefile);
533
534                         sprintf(logtext + strlen(logtext), ":%d)", 0);
535                 }
536
537         } else
538                 strcat(logtext, "call_java_method");
539
540         log_text(logtext);
541 }
542
543
544 /* trace_exception_builtin *****************************************************
545
546    Traces an exception which is thrown by builtin_throw_exception.
547
548 *******************************************************************************/
549
550 void trace_exception_builtin(java_handle_t* h)
551 {
552         char                *logtext;
553         s4                   logtextlen;
554
555         java_lang_Throwable jlt(h);
556
557         // Get detail message.
558         java_handle_t* s = NULL;
559
560         if (jlt.get_handle() != NULL)
561                 s = jlt.get_detailMessage();
562
563         java_lang_String jls(s);
564
565         /* calculate message length */
566
567         logtextlen = strlen("Builtin exception thrown: ") + strlen("0");
568
569         if (jlt.get_handle() != NULL) {
570                 logtextlen += utf_bytes(jlt.get_vftbl()->clazz->name);
571
572                 if (jls.get_handle()) {
573                         CharArray ca(jls.get_value());
574                         // FIXME This is not handle capable!
575                         uint16_t* ptr = (uint16_t*) ca.get_raw_data_ptr();
576                         logtextlen += strlen(": ") +
577                                 u2_utflength(ptr + jls.get_offset(), jls.get_count());
578                 }
579         } 
580         else {
581                 logtextlen += strlen("(nil)");
582         }
583
584         // Create new dump memory area.
585         DumpMemoryArea dma;
586
587         logtext = (char*) DumpMemory::allocate(sizeof(char) * logtextlen);
588
589         strcpy(logtext, "Builtin exception thrown: ");
590
591         if (jlt.get_handle()) {
592                 utf_cat_classname(logtext, jlt.get_vftbl()->clazz->name);
593
594                 if (s) {
595                         char *buf;
596
597                         buf = javastring_tochar(jls.get_handle());
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
610 } // extern "C"
611
612 #endif /* !defined(NDEBUG) */
613
614
615 /*
616  * These are local overrides for various environment variables in Emacs.
617  * Please do not remove this and leave it at the end of the file, where
618  * Emacs will automagically detect them.
619  * ---------------------------------------------------------------------
620  * Local variables:
621  * mode: c++
622  * indent-tabs-mode: t
623  * c-basic-offset: 4
624  * tab-width: 4
625  * End:
626  * vim:noexpandtab:sw=4:ts=4:
627  */