* Removed all Id tags.
[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 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25 */
26
27 #include "config.h"
28
29 #include "arch.h"
30 #include "md-abi.h"
31
32 #include "mm/memory.h"
33
34 #if defined(ENABLE_THREADS)
35 #include "threads/native/threads.h"
36 #else
37 #include "threads/none/threads.h"
38 #endif
39
40 #include "toolbox/logging.h"
41
42 #include "vm/global.h"
43 #include "vm/stringlocal.h"
44 #include "vm/jit/codegen-common.h"
45 #include "vm/jit/trace.h"
46 #include "vm/jit/show.h"
47
48 #include "vmcore/utf8.h"
49
50 #include <stdio.h>
51
52 #if !defined(NDEBUG)
53
54 #if !defined(ENABLE_THREADS)
55 s4 _no_threads_tracejavacallindent = 0;
56 u4 _no_threads_tracejavacallcount= 0;
57 #endif
58
59 /* _array_load_param **********************************************************
60  
61    Returns the argument specified by pd and td from one of the passed arrays
62    and returns it.
63
64 *******************************************************************************/
65
66 static imm_union _array_load_param(paramdesc *pd, typedesc *td, uint64_t *arg_regs, uint64_t *stack) {
67         imm_union ret;
68
69         switch (td->type) {
70                 case TYPE_INT:
71                 case TYPE_ADR:
72                         if (pd->inmemory) {
73 #if (SIZEOF_VOID_P == 8)
74                                 ret.l = (int64_t)stack[pd->index];
75 #else
76                                 ret.l = *(int32_t *)(stack + pd->index);
77 #endif
78                         } else {
79                                 ret.l = arg_regs[pd->index];
80                         }
81                         break;
82                 case TYPE_LNG:
83                         if (pd->inmemory) {
84                                 ret.l = (int64_t)stack[pd->index];
85                         } else {
86 #if (SIZEOF_VOID_P == 8)
87                                 ret.l = (int64_t)arg_regs[pd->index];
88 #else
89                                 ret.l = (int64_t)(
90                                         (arg_regs[GET_HIGH_REG(pd->index)] << 32) |
91                                         (arg_regs[GET_LOW_REG(pd->index)] & 0xFFFFFFFF)
92                                 );
93 #endif
94                         }
95                         break;
96                 case TYPE_FLT:
97                         if (pd->inmemory) {
98                                 ret.l = (int64_t)stack[pd->index];
99                         } else {
100                                 ret.l = (int64_t)arg_regs[pd->index + INT_ARG_CNT];
101                         }
102                         break;
103                 case TYPE_DBL:
104                         if (pd->inmemory) {
105                                 ret.l = (int64_t)stack[pd->index];
106                         } else {
107                                 ret.l = (int64_t)arg_regs[pd->index + INT_ARG_CNT];
108                         }
109                         break;
110         }
111
112         return ret;
113 }
114
115 /* _array_load_return_value ***************************************************
116
117    Loads the proper return value form the return registers array and returns it.
118
119 *******************************************************************************/
120
121 static imm_union _array_load_return_value(typedesc *td, uint64_t *return_regs) {
122         imm_union ret;
123
124         switch (td->type) {
125                 case TYPE_INT:
126                 case TYPE_ADR:
127                         ret.l = return_regs[0];
128                         break;
129                 case TYPE_LNG:
130 #if (SIZEOF_VOID_P == 8)
131                         ret.l = (int64_t)return_regs[0];
132 #else
133                         ret.l = (int64_t)(
134                                 (return_regs[0] << 32) | (return_regs[1] & 0xFFFFFFFF)
135                         );
136 #endif
137                         break;
138                 case TYPE_FLT:
139                         ret.l = (int64_t)return_regs[2];
140                         break;
141                 case TYPE_DBL:
142                         ret.l = (int64_t)return_regs[2];
143                         break;
144         }
145
146         return ret;
147 }
148
149 static char *trace_java_call_print_argument(char *logtext, s4 *logtextlen,
150                                                                                 typedesc *paramtype, imm_union imu)
151 {
152         java_handle_t     *o;
153         classinfo         *c;
154         utf               *u;
155         u4                 len;
156
157         switch (paramtype->type) {
158         case TYPE_INT:
159                 sprintf(logtext + strlen(logtext), "%d (0x%08x)", (int32_t)imu.l, (int32_t)imu.l);
160                 break;
161
162         case TYPE_LNG:
163 #if SIZEOF_VOID_P == 4
164                 sprintf(logtext + strlen(logtext), "%lld (0x%016llx)", imu.l, imu.l);
165 #else
166                 sprintf(logtext + strlen(logtext), "%ld (0x%016lx)", imu.l, imu.l);
167 #endif
168                 break;
169
170         case TYPE_FLT:
171                 sprintf(logtext + strlen(logtext), "%g (0x%08x)", imu.f, imu.i);
172                 break;
173
174         case TYPE_DBL:
175 #if SIZEOF_VOID_P == 4
176                 sprintf(logtext + strlen(logtext), "%g (0x%016llx)", imu.d, imu.l);
177 #else
178                 sprintf(logtext + strlen(logtext), "%g (0x%016lx)", imu.d, imu.l);
179 #endif
180                 break;
181
182         case TYPE_ADR:
183 #if SIZEOF_VOID_P == 4
184                 sprintf(logtext + strlen(logtext), "0x%08x", (ptrint) imu.l);
185 #else
186                 sprintf(logtext + strlen(logtext), "0x%016lx", (ptrint) imu.l);
187 #endif
188
189                 /* cast to java.lang.Object */
190
191                 o = (java_handle_t *) (ptrint) imu.l;
192
193                 /* check return argument for java.lang.Class or java.lang.String */
194
195                 if (o != NULL) {
196                         if (o->vftbl->class == class_java_lang_String) {
197                                 /* get java.lang.String object and the length of the
198                                    string */
199
200                                 u = javastring_toutf(o, false);
201
202                                 len = strlen(" (String = \"") + utf_bytes(u) + strlen("\")");
203
204                                 /* realloc memory for string length */
205
206                                 logtext = DMREALLOC(logtext, char, *logtextlen, *logtextlen + len);
207                                 *logtextlen += len;
208
209                                 /* convert to utf8 string and strcat it to the logtext */
210
211                                 strcat(logtext, " (String = \"");
212                                 utf_cat(logtext, u);
213                                 strcat(logtext, "\")");
214                         }
215                         else {
216                                 if (o->vftbl->class == class_java_lang_Class) {
217                                         /* if the object returned is a java.lang.Class
218                                            cast it to classinfo structure and get the name
219                                            of the class */
220
221                                         c = (classinfo *) o;
222
223                                         u = c->name;
224                                 }
225                                 else {
226                                         /* if the object returned is not a java.lang.String or
227                                            a java.lang.Class just print the name of the class */
228
229                                         u = o->vftbl->class->name;
230                                 }
231
232                                 len = strlen(" (Class = \"") + utf_bytes(u) + strlen("\")");
233
234                                 /* realloc memory for string length */
235
236                                 logtext = DMREALLOC(logtext, char, *logtextlen, *logtextlen + len);
237                                 *logtextlen += len;
238
239                                 /* strcat to the logtext */
240
241                                 strcat(logtext, " (Class = \"");
242                                 utf_cat_classname(logtext, u);
243                                 strcat(logtext, "\")");
244                         }
245                 }
246         }
247
248         return logtext;
249 }
250
251 /* trace_java_call_enter ******************************************************
252  
253    Traces an entry into a java method.
254
255    arg_regs: Array of size ARG_CNT containing all argument registers in
256    the same format as in asm_vm_call_method. The array is usually allocated
257    on the stack and used for restoring the argument registers later.
258
259    stack: Pointer to first on stack argument in the same format passed to 
260    asm_vm_call_method.
261
262 *******************************************************************************/
263
264 void trace_java_call_enter(methodinfo *m, uint64_t *arg_regs, uint64_t *stack) {
265         methoddesc *md;
266         paramdesc *pd;
267         typedesc *td;
268         imm_union arg;
269         char       *logtext;
270         s4          logtextlen;
271         s4          dumpsize;
272         s4          i;
273         s4          pos;
274
275 #if defined(ENABLE_DEBUG_FILTER)
276         if (! show_filters_test_verbosecall_enter(m)) return;
277 #endif
278
279 #if defined(ENABLE_VMLOG)
280         vmlog_cacao_enter_method(m);
281         return;
282 #endif
283
284         md = m->parseddesc;
285
286         /* calculate message length */
287
288         logtextlen =
289                 strlen("4294967295 ") +
290                 strlen("-2147483647-") +        /* INT_MAX should be sufficient       */
291                 TRACEJAVACALLINDENT +
292                 strlen("called: ") +
293                 utf_bytes(m->class->name) +
294                 strlen(".") +
295                 utf_bytes(m->name) +
296                 utf_bytes(m->descriptor);
297
298         /* Actually it's not possible to have all flags printed, but:
299            safety first! */
300
301         logtextlen +=
302                 strlen(" PUBLIC") +
303                 strlen(" PRIVATE") +
304                 strlen(" PROTECTED") +
305                 strlen(" STATIC") +
306                 strlen(" FINAL") +
307                 strlen(" SYNCHRONIZED") +
308                 strlen(" VOLATILE") +
309                 strlen(" TRANSIENT") +
310                 strlen(" NATIVE") +
311                 strlen(" INTERFACE") +
312                 strlen(" ABSTRACT");
313
314         /* add maximal argument length */
315
316         logtextlen +=
317                 strlen("(") +
318                 strlen("-9223372036854775808 (0x123456789abcdef0), ") * md->paramcount +
319                 strlen("...(255)") +
320                 strlen(")");
321
322         /* allocate memory */
323
324         dumpsize = dump_size();
325
326         logtext = DMNEW(char, logtextlen);
327
328         TRACEJAVACALLCOUNT++;
329
330         sprintf(logtext, "%10d ", TRACEJAVACALLCOUNT);
331         sprintf(logtext + strlen(logtext), "-%d-", TRACEJAVACALLINDENT);
332
333         pos = strlen(logtext);
334
335         for (i = 0; i < TRACEJAVACALLINDENT; i++)
336                 logtext[pos++] = '\t';
337
338         strcpy(logtext + pos, "called: ");
339
340         utf_cat_classname(logtext, m->class->name);
341         strcat(logtext, ".");
342         utf_cat(logtext, m->name);
343         utf_cat(logtext, m->descriptor);
344
345         if (m->flags & ACC_PUBLIC)       strcat(logtext, " PUBLIC");
346         if (m->flags & ACC_PRIVATE)      strcat(logtext, " PRIVATE");
347         if (m->flags & ACC_PROTECTED)    strcat(logtext, " PROTECTED");
348         if (m->flags & ACC_STATIC)       strcat(logtext, " STATIC");
349         if (m->flags & ACC_FINAL)        strcat(logtext, " FINAL");
350         if (m->flags & ACC_SYNCHRONIZED) strcat(logtext, " SYNCHRONIZED");
351         if (m->flags & ACC_VOLATILE)     strcat(logtext, " VOLATILE");
352         if (m->flags & ACC_TRANSIENT)    strcat(logtext, " TRANSIENT");
353         if (m->flags & ACC_NATIVE)       strcat(logtext, " NATIVE");
354         if (m->flags & ACC_INTERFACE)    strcat(logtext, " INTERFACE");
355         if (m->flags & ACC_ABSTRACT)     strcat(logtext, " ABSTRACT");
356
357         strcat(logtext, "(");
358
359         for (i = 0; i < md->paramcount; ++i) {
360                 pd = &md->params[i];
361                 td = &md->paramtypes[i];
362                 arg = _array_load_param(pd, td, arg_regs, stack);
363                 logtext = trace_java_call_print_argument(
364                         logtext, &logtextlen, td, arg
365                 );
366                 if (i != (md->paramcount - 1)) {
367                         strcat(logtext, ", ");
368                 }
369         }
370
371         strcat(logtext, ")");
372
373         log_text(logtext);
374
375         /* release memory */
376
377         dump_release(dumpsize);
378
379         TRACEJAVACALLINDENT++;
380
381 }
382
383 /* trace_java_call_exit ********************************************************
384  
385    Traces an exit form a java method.
386
387    return_regs: Array of size 3 containing return registers:
388      [0] : REG_RESULT
389          [1] : REG_RESULT2 (if available on architecture)
390          [2] : REG_FRESULT
391    The array is usually allocated on the stack and used for restoring the
392    registers later. The format of the array is the same as the format of 
393    register arguments passed to asm_vm_call_method.
394
395 *******************************************************************************/
396
397 void trace_java_call_exit(methodinfo *m, uint64_t *return_regs)
398 {
399         methoddesc *md;
400         char       *logtext;
401         s4          logtextlen;
402         s4          dumpsize;
403         s4          i;
404         s4          pos;
405         imm_union   val;
406
407 #if defined(ENABLE_DEBUG_FILTER)
408         if (! show_filters_test_verbosecall_exit(m)) return;
409 #endif
410
411 #if defined(ENABLE_VMLOG)
412         vmlog_cacao_leave_method(m);
413         return;
414 #endif
415
416         md = m->parseddesc;
417
418         /* calculate message length */
419
420         logtextlen =
421                 strlen("4294967295 ") +
422                 strlen("-2147483647-") +        /* INT_MAX should be sufficient       */
423                 TRACEJAVACALLINDENT +
424                 strlen("finished: ") +
425                 utf_bytes(m->class->name) +
426                 strlen(".") +
427                 utf_bytes(m->name) +
428                 utf_bytes(m->descriptor) +
429                 strlen(" SYNCHRONIZED") + strlen("(") + strlen(")");
430
431         /* add maximal argument length */
432
433         logtextlen += strlen("->0.4872328470301428 (0x0123456789abcdef)");
434
435         /* allocate memory */
436
437         dumpsize = dump_size();
438
439         logtext = DMNEW(char, logtextlen);
440
441         /* outdent the log message */
442
443         if (TRACEJAVACALLINDENT)
444                 TRACEJAVACALLINDENT--;
445         else
446                 log_text("WARNING: unmatched TRACEJAVACALLINDENT--");
447
448         /* generate the message */
449
450         sprintf(logtext, "           ");
451         sprintf(logtext + strlen(logtext), "-%d-", TRACEJAVACALLINDENT);
452
453         pos = strlen(logtext);
454
455         for (i = 0; i < TRACEJAVACALLINDENT; i++)
456                 logtext[pos++] = '\t';
457
458         strcpy(logtext + pos, "finished: ");
459         utf_cat_classname(logtext, m->class->name);
460         strcat(logtext, ".");
461         utf_cat(logtext, m->name);
462         utf_cat(logtext, m->descriptor);
463
464         if (!IS_VOID_TYPE(md->returntype.type)) {
465                 strcat(logtext, "->");
466                 val = _array_load_return_value(&md->returntype, return_regs);
467
468                 logtext =
469                         trace_java_call_print_argument(logtext, &logtextlen, &md->returntype, val);
470         }
471
472         log_text(logtext);
473
474         /* release memory */
475
476         dump_release(dumpsize);
477
478 }
479
480 #endif /* !defined(NDEBUG) */
481
482 /*
483  * These are local overrides for various environment variables in Emacs.
484  * Please do not remove this and leave it at the end of the file, where
485  * Emacs will automagically detect them.
486  * ---------------------------------------------------------------------
487  * Local variables:
488  * mode: c
489  * indent-tabs-mode: t
490  * c-basic-offset: 4
491  * tab-width: 4
492  * End:
493  * vim:noexpandtab:sw=4:ts=4:
494  */