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