* src/vm/builtin.c (builtintable_init): Create builtin stubs for
[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 8321 2007-08-16 11:37:25Z michi $
26
27 */
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 void trace_java_call_enter(methodinfo *m, uint64_t *arg_regs, uint64_t *stack) {
252         methoddesc *md;
253         paramdesc *pd;
254         typedesc *td;
255         imm_union arg;
256         char       *logtext;
257         s4          logtextlen;
258         s4          dumpsize;
259         s4          i;
260         s4          pos;
261
262 #if defined(ENABLE_DEBUG_FILTER)
263         if (! show_filters_test_verbosecall_enter(m)) return;
264 #endif
265
266 #if defined(ENABLE_VMLOG)
267         vmlog_cacao_enter_method(m);
268         return;
269 #endif
270
271         md = m->parseddesc;
272
273         /* calculate message length */
274
275         logtextlen =
276                 strlen("4294967295 ") +
277                 strlen("-2147483647-") +        /* INT_MAX should be sufficient       */
278                 TRACEJAVACALLINDENT +
279                 strlen("called: ") +
280                 utf_bytes(m->class->name) +
281                 strlen(".") +
282                 utf_bytes(m->name) +
283                 utf_bytes(m->descriptor);
284
285         /* Actually it's not possible to have all flags printed, but:
286            safety first! */
287
288         logtextlen +=
289                 strlen(" PUBLIC") +
290                 strlen(" PRIVATE") +
291                 strlen(" PROTECTED") +
292                 strlen(" STATIC") +
293                 strlen(" FINAL") +
294                 strlen(" SYNCHRONIZED") +
295                 strlen(" VOLATILE") +
296                 strlen(" TRANSIENT") +
297                 strlen(" NATIVE") +
298                 strlen(" INTERFACE") +
299                 strlen(" ABSTRACT");
300
301         /* add maximal argument length */
302
303         logtextlen +=
304                 strlen("(") +
305                 strlen("-9223372036854775808 (0x123456789abcdef0), ") * md->paramcount +
306                 strlen("...(255)") +
307                 strlen(")");
308
309         /* allocate memory */
310
311         dumpsize = dump_size();
312
313         logtext = DMNEW(char, logtextlen);
314
315         TRACEJAVACALLCOUNT++;
316
317         sprintf(logtext, "%10d ", TRACEJAVACALLCOUNT);
318         sprintf(logtext + strlen(logtext), "-%d-", TRACEJAVACALLINDENT);
319
320         pos = strlen(logtext);
321
322         for (i = 0; i < TRACEJAVACALLINDENT; i++)
323                 logtext[pos++] = '\t';
324
325         strcpy(logtext + pos, "called: ");
326
327         utf_cat_classname(logtext, m->class->name);
328         strcat(logtext, ".");
329         utf_cat(logtext, m->name);
330         utf_cat(logtext, m->descriptor);
331
332         if (m->flags & ACC_PUBLIC)       strcat(logtext, " PUBLIC");
333         if (m->flags & ACC_PRIVATE)      strcat(logtext, " PRIVATE");
334         if (m->flags & ACC_PROTECTED)    strcat(logtext, " PROTECTED");
335         if (m->flags & ACC_STATIC)       strcat(logtext, " STATIC");
336         if (m->flags & ACC_FINAL)        strcat(logtext, " FINAL");
337         if (m->flags & ACC_SYNCHRONIZED) strcat(logtext, " SYNCHRONIZED");
338         if (m->flags & ACC_VOLATILE)     strcat(logtext, " VOLATILE");
339         if (m->flags & ACC_TRANSIENT)    strcat(logtext, " TRANSIENT");
340         if (m->flags & ACC_NATIVE)       strcat(logtext, " NATIVE");
341         if (m->flags & ACC_INTERFACE)    strcat(logtext, " INTERFACE");
342         if (m->flags & ACC_ABSTRACT)     strcat(logtext, " ABSTRACT");
343
344         strcat(logtext, "(");
345
346         for (i = 0; i < md->paramcount; ++i) {
347                 pd = &md->params[i];
348                 td = &md->paramtypes[i];
349                 arg = _array_load_param(pd, td, arg_regs, stack);
350                 logtext = trace_java_call_print_argument(
351                         logtext, &logtextlen, td, arg
352                 );
353                 if (i != (md->paramcount - 1)) {
354                         strcat(logtext, ", ");
355                 }
356         }
357
358         strcat(logtext, ")");
359
360         log_text(logtext);
361
362         /* release memory */
363
364         dump_release(dumpsize);
365
366         TRACEJAVACALLINDENT++;
367
368 }
369
370 void trace_java_call_exit(methodinfo *m, uint64_t *return_regs)
371 {
372         methoddesc *md;
373         char       *logtext;
374         s4          logtextlen;
375         s4          dumpsize;
376         s4          i;
377         s4          pos;
378         imm_union   val;
379
380 #if defined(ENABLE_DEBUG_FILTER)
381         if (! show_filters_test_verbosecall_exit(m)) return;
382 #endif
383
384 #if defined(ENABLE_VMLOG)
385         vmlog_cacao_leave_method(m);
386         return;
387 #endif
388
389         md = m->parseddesc;
390
391         /* calculate message length */
392
393         logtextlen =
394                 strlen("4294967295 ") +
395                 strlen("-2147483647-") +        /* INT_MAX should be sufficient       */
396                 TRACEJAVACALLINDENT +
397                 strlen("finished: ") +
398                 utf_bytes(m->class->name) +
399                 strlen(".") +
400                 utf_bytes(m->name) +
401                 utf_bytes(m->descriptor) +
402                 strlen(" SYNCHRONIZED") + strlen("(") + strlen(")");
403
404         /* add maximal argument length */
405
406         logtextlen += strlen("->0.4872328470301428 (0x0123456789abcdef)");
407
408         /* allocate memory */
409
410         dumpsize = dump_size();
411
412         logtext = DMNEW(char, logtextlen);
413
414         /* outdent the log message */
415
416         if (TRACEJAVACALLINDENT)
417                 TRACEJAVACALLINDENT--;
418         else
419                 log_text("WARNING: unmatched TRACEJAVACALLINDENT--");
420
421         /* generate the message */
422
423         sprintf(logtext, "           ");
424         sprintf(logtext + strlen(logtext), "-%d-", TRACEJAVACALLINDENT);
425
426         pos = strlen(logtext);
427
428         for (i = 0; i < TRACEJAVACALLINDENT; i++)
429                 logtext[pos++] = '\t';
430
431         strcpy(logtext + pos, "finished: ");
432         utf_cat_classname(logtext, m->class->name);
433         strcat(logtext, ".");
434         utf_cat(logtext, m->name);
435         utf_cat(logtext, m->descriptor);
436
437         if (!IS_VOID_TYPE(md->returntype.type)) {
438                 strcat(logtext, "->");
439                 val = _array_load_return_value(&md->returntype, return_regs);
440
441                 logtext =
442                         trace_java_call_print_argument(logtext, &logtextlen, &md->returntype, val);
443         }
444
445         log_text(logtext);
446
447         /* release memory */
448
449         dump_release(dumpsize);
450
451 }
452
453 #endif /* !defined(NDEBUG) */
454