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