* src/native/jni.h: Removed.
[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.h"
34
35 #include "native/llni.h"
36
37 #include "threads/thread.hpp"
38
39 #include "toolbox/logging.h"
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.h"
49 #include "vm/jit/codegen-common.h"
50 #include "vm/jit/trace.hpp"
51 #include "vm/jit/show.h"
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_object_t *) (ptrint) 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 = DMREALLOC(logtext, char, *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 = DMREALLOC(logtext, char, *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         int32_t     dumpmarker;
205
206         /* We don't trace builtin functions here because the argument
207            passing happens via the native ABI and does not fit these
208            functions. */
209
210         if (method_is_builtin(m))
211                 return;
212
213 #if defined(ENABLE_DEBUG_FILTER)
214         if (!show_filters_test_verbosecall_enter(m))
215                 return;
216 #endif
217
218 #if defined(ENABLE_VMLOG)
219         vmlog_cacao_enter_method(m);
220         return;
221 #endif
222
223         md = m->parseddesc;
224
225         /* calculate message length */
226
227         logtextlen =
228                 strlen("4294967295 ") +
229                 strlen("-2147483647-") +        /* INT_MAX should be sufficient       */
230                 TRACEJAVACALLINDENT +
231                 strlen("called: ") +
232                 ((m->clazz == NULL) ? strlen("NULL") : utf_bytes(m->clazz->name)) +
233                 strlen(".") +
234                 utf_bytes(m->name) +
235                 utf_bytes(m->descriptor);
236
237         /* Actually it's not possible to have all flags printed, but:
238            safety first! */
239
240         logtextlen +=
241                 strlen(" PUBLIC") +
242                 strlen(" PRIVATE") +
243                 strlen(" PROTECTED") +
244                 strlen(" STATIC") +
245                 strlen(" FINAL") +
246                 strlen(" SYNCHRONIZED") +
247                 strlen(" VOLATILE") +
248                 strlen(" TRANSIENT") +
249                 strlen(" NATIVE") +
250                 strlen(" INTERFACE") +
251                 strlen(" ABSTRACT") +
252                 strlen(" METHOD_BUILTIN");
253
254         /* add maximal argument length */
255
256         logtextlen +=
257                 strlen("(") +
258                 strlen("-9223372036854775808 (0x123456789abcdef0), ") * md->paramcount +
259                 strlen("...(255)") +
260                 strlen(")");
261
262         /* allocate memory */
263
264         DMARKER;
265
266         logtext = DMNEW(char, logtextlen);
267
268         TRACEJAVACALLCOUNT++;
269
270         sprintf(logtext, "%10d ", TRACEJAVACALLCOUNT);
271         sprintf(logtext + strlen(logtext), "-%d-", TRACEJAVACALLINDENT);
272
273         pos = strlen(logtext);
274
275         for (i = 0; i < TRACEJAVACALLINDENT; i++)
276                 logtext[pos++] = '\t';
277
278         strcpy(logtext + pos, "called: ");
279
280         if (m->clazz != NULL)
281                 utf_cat_classname(logtext, m->clazz->name);
282         else
283                 strcat(logtext, "NULL");
284         strcat(logtext, ".");
285         utf_cat(logtext, m->name);
286         utf_cat(logtext, m->descriptor);
287
288         if (m->flags & ACC_PUBLIC)         strcat(logtext, " PUBLIC");
289         if (m->flags & ACC_PRIVATE)        strcat(logtext, " PRIVATE");
290         if (m->flags & ACC_PROTECTED)      strcat(logtext, " PROTECTED");
291         if (m->flags & ACC_STATIC)         strcat(logtext, " STATIC");
292         if (m->flags & ACC_FINAL)          strcat(logtext, " FINAL");
293         if (m->flags & ACC_SYNCHRONIZED)   strcat(logtext, " SYNCHRONIZED");
294         if (m->flags & ACC_VOLATILE)       strcat(logtext, " VOLATILE");
295         if (m->flags & ACC_TRANSIENT)      strcat(logtext, " TRANSIENT");
296         if (m->flags & ACC_NATIVE)         strcat(logtext, " NATIVE");
297         if (m->flags & ACC_INTERFACE)      strcat(logtext, " INTERFACE");
298         if (m->flags & ACC_ABSTRACT)       strcat(logtext, " ABSTRACT");
299
300         strcat(logtext, "(");
301
302         for (i = 0; i < md->paramcount; ++i) {
303                 arg = argument_jitarray_load(md, i, arg_regs, stack);
304                 logtext = trace_java_call_print_argument(m, logtext, &logtextlen,
305                                                                                                  &md->paramtypes[i], arg);
306                 if (i != (md->paramcount - 1)) {
307                         strcat(logtext, ", ");
308                 }
309         }
310
311         strcat(logtext, ")");
312
313         log_text(logtext);
314
315         /* release memory */
316
317         DRELEASE;
318
319         TRACEJAVACALLINDENT++;
320
321 }
322
323 /* trace_java_call_exit ********************************************************
324
325    Traces an exit form a java method.
326
327    return_regs: Array of size 1 containing return register.
328    The array is usually allocated on the stack and used for restoring the
329    registers later.
330
331 *******************************************************************************/
332
333 void trace_java_call_exit(methodinfo *m, uint64_t *return_regs)
334 {
335         methoddesc *md;
336         char       *logtext;
337         s4          logtextlen;
338         s4          i;
339         s4          pos;
340         imm_union   val;
341         int32_t     dumpmarker;
342
343         /* We don't trace builtin functions here because the argument
344            passing happens via the native ABI and does not fit these
345            functions. */
346
347         if (method_is_builtin(m))
348                 return;
349
350 #if defined(ENABLE_DEBUG_FILTER)
351         if (!show_filters_test_verbosecall_exit(m))
352                 return;
353 #endif
354
355 #if defined(ENABLE_VMLOG)
356         vmlog_cacao_leave_method(m);
357         return;
358 #endif
359
360         md = m->parseddesc;
361
362         /* outdent the log message */
363
364         if (TRACEJAVACALLINDENT)
365                 TRACEJAVACALLINDENT--;
366         else
367                 log_text("trace_java_call_exit: WARNING: unmatched unindent");
368
369         /* calculate message length */
370
371         logtextlen =
372                 strlen("4294967295 ") +
373                 strlen("-2147483647-") +        /* INT_MAX should be sufficient       */
374                 TRACEJAVACALLINDENT +
375                 strlen("finished: ") +
376                 ((m->clazz == NULL) ? strlen("NULL") : utf_bytes(m->clazz->name)) +
377                 strlen(".") +
378                 utf_bytes(m->name) +
379                 utf_bytes(m->descriptor) +
380                 strlen(" SYNCHRONIZED") + strlen("(") + strlen(")");
381
382         /* add maximal argument length */
383
384         logtextlen += strlen("->0.4872328470301428 (0x0123456789abcdef)");
385
386         /* allocate memory */
387
388         DMARKER;
389
390         logtext = DMNEW(char, logtextlen);
391
392         /* generate the message */
393
394         sprintf(logtext, "           ");
395         sprintf(logtext + strlen(logtext), "-%d-", TRACEJAVACALLINDENT);
396
397         pos = strlen(logtext);
398
399         for (i = 0; i < TRACEJAVACALLINDENT; i++)
400                 logtext[pos++] = '\t';
401
402         strcpy(logtext + pos, "finished: ");
403         if (m->clazz != NULL)
404                 utf_cat_classname(logtext, m->clazz->name);
405         else
406                 strcat(logtext, "NULL");
407         strcat(logtext, ".");
408         utf_cat(logtext, m->name);
409         utf_cat(logtext, m->descriptor);
410
411         if (!IS_VOID_TYPE(md->returntype.type)) {
412                 strcat(logtext, "->");
413                 val = argument_jitreturn_load(md, return_regs);
414
415                 logtext =
416                         trace_java_call_print_argument(m, logtext, &logtextlen,
417                                                                                    &md->returntype, val);
418         }
419
420         log_text(logtext);
421
422         /* release memory */
423
424         DRELEASE;
425 }
426
427
428 /* trace_exception *************************************************************
429
430    Traces an exception which is handled by exceptions_handle_exception.
431
432 *******************************************************************************/
433
434 void trace_exception(java_object_t *xptr, methodinfo *m, void *pos)
435 {
436         char *logtext;
437         s4    logtextlen;
438         codeinfo *code;
439         int32_t   dumpmarker;
440
441         /* calculate message length */
442
443         if (xptr) {
444                 logtextlen =
445                         strlen("Exception ") + utf_bytes(xptr->vftbl->clazz->name);
446         } 
447         else {
448                 logtextlen = strlen("Some Throwable");
449         }
450
451         logtextlen += strlen(" thrown in ");
452
453         if (m) {
454                 logtextlen +=
455                         utf_bytes(m->clazz->name) +
456                         strlen(".") +
457                         utf_bytes(m->name) +
458                         utf_bytes(m->descriptor) +
459                         strlen("(NOSYNC,NATIVE");
460
461 #if SIZEOF_VOID_P == 8
462                 logtextlen +=
463                         strlen(")(0x123456789abcdef0) at position 0x123456789abcdef0 (");
464 #else
465                 logtextlen += strlen(")(0x12345678) at position 0x12345678 (");
466 #endif
467
468                 if (m->clazz->sourcefile == NULL)
469                         logtextlen += strlen("<NO CLASSFILE INFORMATION>");
470                 else
471                         logtextlen += utf_bytes(m->clazz->sourcefile);
472
473                 logtextlen += strlen(":65536)");
474
475         } 
476         else {
477                 logtextlen += strlen("call_java_method");
478         }
479
480         logtextlen += strlen("0");
481
482         /* allocate memory */
483
484         DMARKER;
485
486         logtext = DMNEW(char, logtextlen);
487
488         if (xptr) {
489                 strcpy(logtext, "Exception ");
490                 utf_cat_classname(logtext, xptr->vftbl->clazz->name);
491
492         } else {
493                 strcpy(logtext, "Some Throwable");
494         }
495
496         strcat(logtext, " thrown in ");
497
498         if (m) {
499                 utf_cat_classname(logtext, m->clazz->name);
500                 strcat(logtext, ".");
501                 utf_cat(logtext, m->name);
502                 utf_cat(logtext, m->descriptor);
503
504                 if (m->flags & ACC_SYNCHRONIZED)
505                         strcat(logtext, "(SYNC");
506                 else
507                         strcat(logtext, "(NOSYNC");
508
509                 if (m->flags & ACC_NATIVE) {
510                         strcat(logtext, ",NATIVE");
511
512                         code = m->code;
513
514 #if SIZEOF_VOID_P == 8
515                         sprintf(logtext + strlen(logtext),
516                                         ")(0x%016lx) at position 0x%016lx",
517                                         (ptrint) code->entrypoint, (ptrint) pos);
518 #else
519                         sprintf(logtext + strlen(logtext),
520                                         ")(0x%08x) at position 0x%08x",
521                                         (ptrint) code->entrypoint, (ptrint) pos);
522 #endif
523
524                 } else {
525
526                         /* XXX preliminary: This should get the actual codeinfo */
527                         /* in which the exception happened.                     */
528                         code = m->code;
529                         
530 #if SIZEOF_VOID_P == 8
531                         sprintf(logtext + strlen(logtext),
532                                         ")(0x%016lx) at position 0x%016lx (",
533                                         (ptrint) code->entrypoint, (ptrint) pos);
534 #else
535                         sprintf(logtext + strlen(logtext),
536                                         ")(0x%08x) at position 0x%08x (",
537                                         (ptrint) code->entrypoint, (ptrint) pos);
538 #endif
539
540                         if (m->clazz->sourcefile == NULL)
541                                 strcat(logtext, "<NO CLASSFILE INFORMATION>");
542                         else
543                                 utf_cat(logtext, m->clazz->sourcefile);
544
545                         sprintf(logtext + strlen(logtext), ":%d)", 0);
546                 }
547
548         } else
549                 strcat(logtext, "call_java_method");
550
551         log_text(logtext);
552
553         /* release memory */
554
555         DRELEASE;
556 }
557
558
559 /* trace_exception_builtin *****************************************************
560
561    Traces an exception which is thrown by builtin_throw_exception.
562
563 *******************************************************************************/
564
565 void trace_exception_builtin(java_handle_t* h)
566 {
567         char                *logtext;
568         s4                   logtextlen;
569         int32_t              dumpmarker;
570
571         java_lang_Throwable jlt(h);
572
573         // Get detail message.
574         java_handle_t* s = NULL;
575
576         if (jlt.get_handle() != NULL)
577                 s = jlt.get_detailMessage();
578
579         java_lang_String jls(s);
580
581         /* calculate message length */
582
583         logtextlen = strlen("Builtin exception thrown: ") + strlen("0");
584
585         if (jlt.get_handle() != NULL) {
586                 logtextlen += utf_bytes(jlt.get_vftbl()->clazz->name);
587
588                 if (jls.get_handle()) {
589                         // FIXME This is not handle capable!
590                         logtextlen += strlen(": ") +
591                                 u2_utflength(jls.get_value()->data + jls.get_offset(), jls.get_count());
592                 }
593         } 
594         else {
595                 logtextlen += strlen("(nil)");
596         }
597
598         /* allocate memory */
599
600         DMARKER;
601
602         logtext = DMNEW(char, logtextlen);
603
604         strcpy(logtext, "Builtin exception thrown: ");
605
606         if (jlt.get_handle()) {
607                 utf_cat_classname(logtext, jlt.get_vftbl()->clazz->name);
608
609                 if (s) {
610                         char *buf;
611
612                         buf = javastring_tochar(jls.get_handle());
613                         strcat(logtext, ": ");
614                         strcat(logtext, buf);
615                         MFREE(buf, char, strlen(buf) + 1);
616                 }
617
618         } else {
619                 strcat(logtext, "(nil)");
620         }
621
622         log_text(logtext);
623
624         /* release memory */
625
626         DRELEASE;
627 }
628
629 } // extern "C"
630
631 #endif /* !defined(NDEBUG) */
632
633
634 /*
635  * These are local overrides for various environment variables in Emacs.
636  * Please do not remove this and leave it at the end of the file, where
637  * Emacs will automagically detect them.
638  * ---------------------------------------------------------------------
639  * Local variables:
640  * mode: c++
641  * indent-tabs-mode: t
642  * c-basic-offset: 4
643  * tab-width: 4
644  * End:
645  * vim:noexpandtab:sw=4:ts=4:
646  */