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