1 /* src/vm/jit/trace.c - Functions for tracing from java code.
3 Copyright (C) 1996-2005, 2006, 2007, 2008
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 This file is part of CACAO.
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.
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.
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
32 #include "mm/memory.h"
34 #include "native/jni.h"
35 #include "native/llni.h"
37 #include "native/include/java_lang_String.h"
38 #include "native/include/java_lang_Throwable.h"
40 #include "threads/thread.h"
42 #include "toolbox/logging.h"
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"
51 #include "vmcore/options.h"
52 #include "vmcore/utf8.h"
58 /* global variables ***********************************************************/
60 #if !defined(ENABLE_THREADS)
61 s4 _no_threads_tracejavacallindent = 0;
62 u4 _no_threads_tracejavacallcount= 0;
66 /* trace_java_call_print_argument **********************************************
70 *******************************************************************************/
72 static char *trace_java_call_print_argument(methodinfo *m, char *logtext, s4 *logtextlen, typedesc *paramtype, imm_union imu)
79 switch (paramtype->type) {
81 sprintf(logtext + strlen(logtext), "%d (0x%08x)", (int32_t)imu.l, (int32_t)imu.l);
85 #if SIZEOF_VOID_P == 4
86 sprintf(logtext + strlen(logtext), "%lld (0x%016llx)", imu.l, imu.l);
88 sprintf(logtext + strlen(logtext), "%ld (0x%016lx)", imu.l, imu.l);
93 sprintf(logtext + strlen(logtext), "%g (0x%08x)", imu.f, imu.i);
97 #if SIZEOF_VOID_P == 4
98 sprintf(logtext + strlen(logtext), "%g (0x%016llx)", imu.d, imu.l);
100 sprintf(logtext + strlen(logtext), "%g (0x%016lx)", imu.d, imu.l);
105 #if SIZEOF_VOID_P == 4
106 sprintf(logtext + strlen(logtext), "0x%08x", (ptrint) imu.l);
108 sprintf(logtext + strlen(logtext), "0x%016lx", (ptrint) imu.l);
111 /* Workaround for sun.misc.Unsafe methods. In the future
112 (exact GC) we should check if the address is on the GC
115 if ((m->clazz != NULL) &&
116 (m->clazz->name == utf_new_char("sun/misc/Unsafe")))
119 /* Cast to java.lang.Object. */
121 o = (java_object_t *) (ptrint) imu.l;
123 /* Check return argument for java.lang.Class or
127 if (o->vftbl->clazz == class_java_lang_String) {
128 /* get java.lang.String object and the length of the
131 u = javastring_toutf(o, false);
133 len = strlen(" (String = \"") + utf_bytes(u) + strlen("\")");
135 /* realloc memory for string length */
137 logtext = DMREALLOC(logtext, char, *logtextlen, *logtextlen + len);
140 /* convert to utf8 string and strcat it to the logtext */
142 strcat(logtext, " (String = \"");
144 strcat(logtext, "\")");
147 if (o->vftbl->clazz == class_java_lang_Class) {
148 /* if the object returned is a java.lang.Class
149 cast it to classinfo structure and get the name
157 /* if the object returned is not a java.lang.String or
158 a java.lang.Class just print the name of the class */
160 u = o->vftbl->clazz->name;
163 len = strlen(" (Class = \"") + utf_bytes(u) + strlen("\")");
165 /* realloc memory for string length */
167 logtext = DMREALLOC(logtext, char, *logtextlen, *logtextlen + len);
170 /* strcat to the logtext */
172 strcat(logtext, " (Class = \"");
173 utf_cat_classname(logtext, u);
174 strcat(logtext, "\")");
182 /* trace_java_call_enter ******************************************************
184 Traces an entry into a java method.
186 arg_regs: Array containing all argument registers as int64_t values in
187 the same order as listed in m->methoddesc. The array is usually allocated
188 on the stack and used for restoring the argument registers later.
190 stack: Pointer to first on stack argument in the same format passed to
193 *******************************************************************************/
195 void trace_java_call_enter(methodinfo *m, uint64_t *arg_regs, uint64_t *stack)
205 #if defined(ENABLE_DEBUG_FILTER)
206 if (!show_filters_test_verbosecall_enter(m))
210 #if defined(ENABLE_VMLOG)
211 vmlog_cacao_enter_method(m);
217 /* calculate message length */
220 strlen("4294967295 ") +
221 strlen("-2147483647-") + /* INT_MAX should be sufficient */
222 TRACEJAVACALLINDENT +
224 ((m->clazz == NULL) ? strlen("NULL") : utf_bytes(m->clazz->name)) +
227 utf_bytes(m->descriptor);
229 /* Actually it's not possible to have all flags printed, but:
235 strlen(" PROTECTED") +
238 strlen(" SYNCHRONIZED") +
239 strlen(" VOLATILE") +
240 strlen(" TRANSIENT") +
242 strlen(" INTERFACE") +
243 strlen(" ABSTRACT") +
244 strlen(" METHOD_BUILTIN");
246 /* add maximal argument length */
250 strlen("-9223372036854775808 (0x123456789abcdef0), ") * md->paramcount +
254 /* allocate memory */
258 logtext = DMNEW(char, logtextlen);
260 TRACEJAVACALLCOUNT++;
262 sprintf(logtext, "%10d ", TRACEJAVACALLCOUNT);
263 sprintf(logtext + strlen(logtext), "-%d-", TRACEJAVACALLINDENT);
265 pos = strlen(logtext);
267 for (i = 0; i < TRACEJAVACALLINDENT; i++)
268 logtext[pos++] = '\t';
270 strcpy(logtext + pos, "called: ");
272 if (m->clazz != NULL)
273 utf_cat_classname(logtext, m->clazz->name);
275 strcat(logtext, "NULL");
276 strcat(logtext, ".");
277 utf_cat(logtext, m->name);
278 utf_cat(logtext, m->descriptor);
280 if (m->flags & ACC_PUBLIC) strcat(logtext, " PUBLIC");
281 if (m->flags & ACC_PRIVATE) strcat(logtext, " PRIVATE");
282 if (m->flags & ACC_PROTECTED) strcat(logtext, " PROTECTED");
283 if (m->flags & ACC_STATIC) strcat(logtext, " STATIC");
284 if (m->flags & ACC_FINAL) strcat(logtext, " FINAL");
285 if (m->flags & ACC_SYNCHRONIZED) strcat(logtext, " SYNCHRONIZED");
286 if (m->flags & ACC_VOLATILE) strcat(logtext, " VOLATILE");
287 if (m->flags & ACC_TRANSIENT) strcat(logtext, " TRANSIENT");
288 if (m->flags & ACC_NATIVE) strcat(logtext, " NATIVE");
289 if (m->flags & ACC_INTERFACE) strcat(logtext, " INTERFACE");
290 if (m->flags & ACC_ABSTRACT) strcat(logtext, " ABSTRACT");
291 if (m->flags & ACC_METHOD_BUILTIN) strcat(logtext, " METHOD_BUILTIN");
293 strcat(logtext, "(");
295 for (i = 0; i < md->paramcount; ++i) {
296 arg = argument_jitarray_load(md, i, arg_regs, stack);
297 logtext = trace_java_call_print_argument(m, logtext, &logtextlen,
298 &md->paramtypes[i], arg);
299 if (i != (md->paramcount - 1)) {
300 strcat(logtext, ", ");
304 strcat(logtext, ")");
312 TRACEJAVACALLINDENT++;
316 /* trace_java_call_exit ********************************************************
318 Traces an exit form a java method.
320 return_regs: Array of size 1 containing return register.
321 The array is usually allocated on the stack and used for restoring the
324 *******************************************************************************/
326 void trace_java_call_exit(methodinfo *m, uint64_t *return_regs)
336 #if defined(ENABLE_DEBUG_FILTER)
337 if (!show_filters_test_verbosecall_exit(m))
341 #if defined(ENABLE_VMLOG)
342 vmlog_cacao_leave_method(m);
348 /* outdent the log message */
350 if (TRACEJAVACALLINDENT)
351 TRACEJAVACALLINDENT--;
353 log_text("trace_java_call_exit: WARNING: unmatched unindent");
355 /* calculate message length */
358 strlen("4294967295 ") +
359 strlen("-2147483647-") + /* INT_MAX should be sufficient */
360 TRACEJAVACALLINDENT +
361 strlen("finished: ") +
362 ((m->clazz == NULL) ? strlen("NULL") : utf_bytes(m->clazz->name)) +
365 utf_bytes(m->descriptor) +
366 strlen(" SYNCHRONIZED") + strlen("(") + strlen(")");
368 /* add maximal argument length */
370 logtextlen += strlen("->0.4872328470301428 (0x0123456789abcdef)");
372 /* allocate memory */
376 logtext = DMNEW(char, logtextlen);
378 /* generate the message */
380 sprintf(logtext, " ");
381 sprintf(logtext + strlen(logtext), "-%d-", TRACEJAVACALLINDENT);
383 pos = strlen(logtext);
385 for (i = 0; i < TRACEJAVACALLINDENT; i++)
386 logtext[pos++] = '\t';
388 strcpy(logtext + pos, "finished: ");
389 if (m->clazz != NULL)
390 utf_cat_classname(logtext, m->clazz->name);
392 strcat(logtext, "NULL");
393 strcat(logtext, ".");
394 utf_cat(logtext, m->name);
395 utf_cat(logtext, m->descriptor);
397 if (!IS_VOID_TYPE(md->returntype.type)) {
398 strcat(logtext, "->");
399 val = argument_jitreturn_load(md, return_regs);
402 trace_java_call_print_argument(m, logtext, &logtextlen,
403 &md->returntype, val);
414 /* trace_exception *************************************************************
416 Traces an exception which is handled by exceptions_handle_exception.
418 *******************************************************************************/
420 void trace_exception(java_object_t *xptr, methodinfo *m, void *pos)
427 /* calculate message length */
431 strlen("Exception ") + utf_bytes(xptr->vftbl->clazz->name);
434 logtextlen = strlen("Some Throwable");
437 logtextlen += strlen(" thrown in ");
441 utf_bytes(m->clazz->name) +
444 utf_bytes(m->descriptor) +
445 strlen("(NOSYNC,NATIVE");
447 #if SIZEOF_VOID_P == 8
449 strlen(")(0x123456789abcdef0) at position 0x123456789abcdef0 (");
451 logtextlen += strlen(")(0x12345678) at position 0x12345678 (");
454 if (m->clazz->sourcefile == NULL)
455 logtextlen += strlen("<NO CLASSFILE INFORMATION>");
457 logtextlen += utf_bytes(m->clazz->sourcefile);
459 logtextlen += strlen(":65536)");
463 logtextlen += strlen("call_java_method");
466 logtextlen += strlen("0");
468 /* allocate memory */
472 logtext = DMNEW(char, logtextlen);
475 strcpy(logtext, "Exception ");
476 utf_cat_classname(logtext, xptr->vftbl->clazz->name);
479 strcpy(logtext, "Some Throwable");
482 strcat(logtext, " thrown in ");
485 utf_cat_classname(logtext, m->clazz->name);
486 strcat(logtext, ".");
487 utf_cat(logtext, m->name);
488 utf_cat(logtext, m->descriptor);
490 if (m->flags & ACC_SYNCHRONIZED)
491 strcat(logtext, "(SYNC");
493 strcat(logtext, "(NOSYNC");
495 if (m->flags & ACC_NATIVE) {
496 strcat(logtext, ",NATIVE");
500 #if SIZEOF_VOID_P == 8
501 sprintf(logtext + strlen(logtext),
502 ")(0x%016lx) at position 0x%016lx",
503 (ptrint) code->entrypoint, (ptrint) pos);
505 sprintf(logtext + strlen(logtext),
506 ")(0x%08x) at position 0x%08x",
507 (ptrint) code->entrypoint, (ptrint) pos);
512 /* XXX preliminary: This should get the actual codeinfo */
513 /* in which the exception happened. */
516 #if SIZEOF_VOID_P == 8
517 sprintf(logtext + strlen(logtext),
518 ")(0x%016lx) at position 0x%016lx (",
519 (ptrint) code->entrypoint, (ptrint) pos);
521 sprintf(logtext + strlen(logtext),
522 ")(0x%08x) at position 0x%08x (",
523 (ptrint) code->entrypoint, (ptrint) pos);
526 if (m->clazz->sourcefile == NULL)
527 strcat(logtext, "<NO CLASSFILE INFORMATION>");
529 utf_cat(logtext, m->clazz->sourcefile);
531 sprintf(logtext + strlen(logtext), ":%d)", 0);
535 strcat(logtext, "call_java_method");
545 /* trace_exception_builtin *****************************************************
547 Traces an exception which is thrown by builtin_throw_exception.
549 *******************************************************************************/
551 void trace_exception_builtin(java_object_t *xptr)
553 java_lang_Throwable *t;
559 t = (java_lang_Throwable *) xptr;
561 /* get detail message */
563 LLNI_field_get_ref(t, detailMessage, s);
565 /* calculate message length */
567 logtextlen = strlen("Builtin exception thrown: ") + strlen("0");
571 utf_bytes(xptr->vftbl->clazz->name);
573 logtextlen += strlen(": ") +
574 u2_utflength(LLNI_field_direct(s, value)->data
575 + LLNI_field_direct(s, offset),
576 LLNI_field_direct(s,count));
580 logtextlen += strlen("(nil)");
583 /* allocate memory */
587 logtext = DMNEW(char, logtextlen);
589 strcpy(logtext, "Builtin exception thrown: ");
592 utf_cat_classname(logtext, xptr->vftbl->clazz->name);
597 buf = javastring_tochar((java_handle_t *) s);
598 strcat(logtext, ": ");
599 strcat(logtext, buf);
600 MFREE(buf, char, strlen(buf) + 1);
604 strcat(logtext, "(nil)");
615 #endif /* !defined(NDEBUG) */
619 * These are local overrides for various environment variables in Emacs.
620 * Please do not remove this and leave it at the end of the file, where
621 * Emacs will automagically detect them.
622 * ---------------------------------------------------------------------
625 * indent-tabs-mode: t
629 * vim:noexpandtab:sw=4:ts=4: