1 /* src/vm/jit/trace.cpp - 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
26 // FIXME For now we export everything as C functions.
36 #include "mm/memory.h"
38 #include "native/jni.h"
39 #include "native/llni.h"
41 #include "native/include/java_lang_String.h"
42 #include "native/include/java_lang_Throwable.h"
44 #include "threads/thread.hpp"
46 #include "toolbox/logging.h"
48 #include "vm/global.h"
49 #include "vm/stringlocal.h"
50 #include "vm/jit/argument.h"
51 #include "vm/jit/codegen-common.h"
52 #include "vm/jit/trace.hpp"
53 #include "vm/jit/show.h"
55 #include "vmcore/globals.hpp"
56 #include "vmcore/options.h"
57 #include "vmcore/utf8.h"
63 /* global variables ***********************************************************/
65 #if !defined(ENABLE_THREADS)
66 s4 _no_threads_tracejavacallindent = 0;
67 u4 _no_threads_tracejavacallcount= 0;
71 /* trace_java_call_print_argument **********************************************
75 *******************************************************************************/
77 static char *trace_java_call_print_argument(methodinfo *m, char *logtext, s4 *logtextlen, typedesc *paramtype, imm_union imu)
84 switch (paramtype->type) {
86 sprintf(logtext + strlen(logtext), "%d (0x%08x)", (int32_t)imu.l, (int32_t)imu.l);
90 #if SIZEOF_VOID_P == 4
91 sprintf(logtext + strlen(logtext), "%lld (0x%016llx)", imu.l, imu.l);
93 sprintf(logtext + strlen(logtext), "%ld (0x%016lx)", imu.l, imu.l);
98 sprintf(logtext + strlen(logtext), "%g (0x%08x)", imu.f, imu.i);
102 #if SIZEOF_VOID_P == 4
103 sprintf(logtext + strlen(logtext), "%g (0x%016llx)", imu.d, imu.l);
105 sprintf(logtext + strlen(logtext), "%g (0x%016lx)", imu.d, imu.l);
110 #if SIZEOF_VOID_P == 4
111 sprintf(logtext + strlen(logtext), "0x%08x", (ptrint) imu.l);
113 sprintf(logtext + strlen(logtext), "0x%016lx", (ptrint) imu.l);
116 /* Workaround for sun.misc.Unsafe methods. In the future
117 (exact GC) we should check if the address is on the GC
120 if ((m->clazz != NULL) &&
121 (m->clazz->name == utf_new_char("sun/misc/Unsafe")))
124 /* Cast to java.lang.Object. */
126 o = (java_object_t *) (ptrint) imu.l;
128 /* Check return argument for java.lang.Class or
132 if (o->vftbl->clazz == class_java_lang_String) {
133 /* get java.lang.String object and the length of the
136 u = javastring_toutf(o, false);
138 len = strlen(" (String = \"") + utf_bytes(u) + strlen("\")");
140 /* realloc memory for string length */
142 logtext = DMREALLOC(logtext, char, *logtextlen, *logtextlen + len);
145 /* convert to utf8 string and strcat it to the logtext */
147 strcat(logtext, " (String = \"");
149 strcat(logtext, "\")");
152 if (o->vftbl->clazz == class_java_lang_Class) {
153 /* if the object returned is a java.lang.Class
154 cast it to classinfo structure and get the name
162 /* if the object returned is not a java.lang.String or
163 a java.lang.Class just print the name of the class */
165 u = o->vftbl->clazz->name;
168 len = strlen(" (Class = \"") + utf_bytes(u) + strlen("\")");
170 /* realloc memory for string length */
172 logtext = DMREALLOC(logtext, char, *logtextlen, *logtextlen + len);
175 /* strcat to the logtext */
177 strcat(logtext, " (Class = \"");
178 utf_cat_classname(logtext, u);
179 strcat(logtext, "\")");
187 /* trace_java_call_enter ******************************************************
189 Traces an entry into a java method.
191 arg_regs: Array containing all argument registers as int64_t values in
192 the same order as listed in m->methoddesc. The array is usually allocated
193 on the stack and used for restoring the argument registers later.
195 stack: Pointer to first on stack argument in the same format passed to
198 *******************************************************************************/
200 void trace_java_call_enter(methodinfo *m, uint64_t *arg_regs, uint64_t *stack)
210 /* We don't trace builtin functions here because the argument
211 passing happens via the native ABI and does not fit these
214 if (method_is_builtin(m))
217 #if defined(ENABLE_DEBUG_FILTER)
218 if (!show_filters_test_verbosecall_enter(m))
222 #if defined(ENABLE_VMLOG)
223 vmlog_cacao_enter_method(m);
229 /* calculate message length */
232 strlen("4294967295 ") +
233 strlen("-2147483647-") + /* INT_MAX should be sufficient */
234 TRACEJAVACALLINDENT +
236 ((m->clazz == NULL) ? strlen("NULL") : utf_bytes(m->clazz->name)) +
239 utf_bytes(m->descriptor);
241 /* Actually it's not possible to have all flags printed, but:
247 strlen(" PROTECTED") +
250 strlen(" SYNCHRONIZED") +
251 strlen(" VOLATILE") +
252 strlen(" TRANSIENT") +
254 strlen(" INTERFACE") +
255 strlen(" ABSTRACT") +
256 strlen(" METHOD_BUILTIN");
258 /* add maximal argument length */
262 strlen("-9223372036854775808 (0x123456789abcdef0), ") * md->paramcount +
266 /* allocate memory */
270 logtext = DMNEW(char, logtextlen);
272 TRACEJAVACALLCOUNT++;
274 sprintf(logtext, "%10d ", TRACEJAVACALLCOUNT);
275 sprintf(logtext + strlen(logtext), "-%d-", TRACEJAVACALLINDENT);
277 pos = strlen(logtext);
279 for (i = 0; i < TRACEJAVACALLINDENT; i++)
280 logtext[pos++] = '\t';
282 strcpy(logtext + pos, "called: ");
284 if (m->clazz != NULL)
285 utf_cat_classname(logtext, m->clazz->name);
287 strcat(logtext, "NULL");
288 strcat(logtext, ".");
289 utf_cat(logtext, m->name);
290 utf_cat(logtext, m->descriptor);
292 if (m->flags & ACC_PUBLIC) strcat(logtext, " PUBLIC");
293 if (m->flags & ACC_PRIVATE) strcat(logtext, " PRIVATE");
294 if (m->flags & ACC_PROTECTED) strcat(logtext, " PROTECTED");
295 if (m->flags & ACC_STATIC) strcat(logtext, " STATIC");
296 if (m->flags & ACC_FINAL) strcat(logtext, " FINAL");
297 if (m->flags & ACC_SYNCHRONIZED) strcat(logtext, " SYNCHRONIZED");
298 if (m->flags & ACC_VOLATILE) strcat(logtext, " VOLATILE");
299 if (m->flags & ACC_TRANSIENT) strcat(logtext, " TRANSIENT");
300 if (m->flags & ACC_NATIVE) strcat(logtext, " NATIVE");
301 if (m->flags & ACC_INTERFACE) strcat(logtext, " INTERFACE");
302 if (m->flags & ACC_ABSTRACT) strcat(logtext, " ABSTRACT");
304 strcat(logtext, "(");
306 for (i = 0; i < md->paramcount; ++i) {
307 arg = argument_jitarray_load(md, i, arg_regs, stack);
308 logtext = trace_java_call_print_argument(m, logtext, &logtextlen,
309 &md->paramtypes[i], arg);
310 if (i != (md->paramcount - 1)) {
311 strcat(logtext, ", ");
315 strcat(logtext, ")");
323 TRACEJAVACALLINDENT++;
327 /* trace_java_call_exit ********************************************************
329 Traces an exit form a java method.
331 return_regs: Array of size 1 containing return register.
332 The array is usually allocated on the stack and used for restoring the
335 *******************************************************************************/
337 void trace_java_call_exit(methodinfo *m, uint64_t *return_regs)
347 /* We don't trace builtin functions here because the argument
348 passing happens via the native ABI and does not fit these
351 if (method_is_builtin(m))
354 #if defined(ENABLE_DEBUG_FILTER)
355 if (!show_filters_test_verbosecall_exit(m))
359 #if defined(ENABLE_VMLOG)
360 vmlog_cacao_leave_method(m);
366 /* outdent the log message */
368 if (TRACEJAVACALLINDENT)
369 TRACEJAVACALLINDENT--;
371 log_text("trace_java_call_exit: WARNING: unmatched unindent");
373 /* calculate message length */
376 strlen("4294967295 ") +
377 strlen("-2147483647-") + /* INT_MAX should be sufficient */
378 TRACEJAVACALLINDENT +
379 strlen("finished: ") +
380 ((m->clazz == NULL) ? strlen("NULL") : utf_bytes(m->clazz->name)) +
383 utf_bytes(m->descriptor) +
384 strlen(" SYNCHRONIZED") + strlen("(") + strlen(")");
386 /* add maximal argument length */
388 logtextlen += strlen("->0.4872328470301428 (0x0123456789abcdef)");
390 /* allocate memory */
394 logtext = DMNEW(char, logtextlen);
396 /* generate the message */
398 sprintf(logtext, " ");
399 sprintf(logtext + strlen(logtext), "-%d-", TRACEJAVACALLINDENT);
401 pos = strlen(logtext);
403 for (i = 0; i < TRACEJAVACALLINDENT; i++)
404 logtext[pos++] = '\t';
406 strcpy(logtext + pos, "finished: ");
407 if (m->clazz != NULL)
408 utf_cat_classname(logtext, m->clazz->name);
410 strcat(logtext, "NULL");
411 strcat(logtext, ".");
412 utf_cat(logtext, m->name);
413 utf_cat(logtext, m->descriptor);
415 if (!IS_VOID_TYPE(md->returntype.type)) {
416 strcat(logtext, "->");
417 val = argument_jitreturn_load(md, return_regs);
420 trace_java_call_print_argument(m, logtext, &logtextlen,
421 &md->returntype, val);
432 /* trace_exception *************************************************************
434 Traces an exception which is handled by exceptions_handle_exception.
436 *******************************************************************************/
438 void trace_exception(java_object_t *xptr, methodinfo *m, void *pos)
445 /* calculate message length */
449 strlen("Exception ") + utf_bytes(xptr->vftbl->clazz->name);
452 logtextlen = strlen("Some Throwable");
455 logtextlen += strlen(" thrown in ");
459 utf_bytes(m->clazz->name) +
462 utf_bytes(m->descriptor) +
463 strlen("(NOSYNC,NATIVE");
465 #if SIZEOF_VOID_P == 8
467 strlen(")(0x123456789abcdef0) at position 0x123456789abcdef0 (");
469 logtextlen += strlen(")(0x12345678) at position 0x12345678 (");
472 if (m->clazz->sourcefile == NULL)
473 logtextlen += strlen("<NO CLASSFILE INFORMATION>");
475 logtextlen += utf_bytes(m->clazz->sourcefile);
477 logtextlen += strlen(":65536)");
481 logtextlen += strlen("call_java_method");
484 logtextlen += strlen("0");
486 /* allocate memory */
490 logtext = DMNEW(char, logtextlen);
493 strcpy(logtext, "Exception ");
494 utf_cat_classname(logtext, xptr->vftbl->clazz->name);
497 strcpy(logtext, "Some Throwable");
500 strcat(logtext, " thrown in ");
503 utf_cat_classname(logtext, m->clazz->name);
504 strcat(logtext, ".");
505 utf_cat(logtext, m->name);
506 utf_cat(logtext, m->descriptor);
508 if (m->flags & ACC_SYNCHRONIZED)
509 strcat(logtext, "(SYNC");
511 strcat(logtext, "(NOSYNC");
513 if (m->flags & ACC_NATIVE) {
514 strcat(logtext, ",NATIVE");
518 #if SIZEOF_VOID_P == 8
519 sprintf(logtext + strlen(logtext),
520 ")(0x%016lx) at position 0x%016lx",
521 (ptrint) code->entrypoint, (ptrint) pos);
523 sprintf(logtext + strlen(logtext),
524 ")(0x%08x) at position 0x%08x",
525 (ptrint) code->entrypoint, (ptrint) pos);
530 /* XXX preliminary: This should get the actual codeinfo */
531 /* in which the exception happened. */
534 #if SIZEOF_VOID_P == 8
535 sprintf(logtext + strlen(logtext),
536 ")(0x%016lx) at position 0x%016lx (",
537 (ptrint) code->entrypoint, (ptrint) pos);
539 sprintf(logtext + strlen(logtext),
540 ")(0x%08x) at position 0x%08x (",
541 (ptrint) code->entrypoint, (ptrint) pos);
544 if (m->clazz->sourcefile == NULL)
545 strcat(logtext, "<NO CLASSFILE INFORMATION>");
547 utf_cat(logtext, m->clazz->sourcefile);
549 sprintf(logtext + strlen(logtext), ":%d)", 0);
553 strcat(logtext, "call_java_method");
563 /* trace_exception_builtin *****************************************************
565 Traces an exception which is thrown by builtin_throw_exception.
567 *******************************************************************************/
569 void trace_exception_builtin(java_object_t *xptr)
571 java_lang_Throwable *t;
577 t = (java_lang_Throwable *) xptr;
579 /* get detail message */
581 LLNI_field_get_ref(t, detailMessage, s);
583 /* calculate message length */
585 logtextlen = strlen("Builtin exception thrown: ") + strlen("0");
589 utf_bytes(xptr->vftbl->clazz->name);
591 logtextlen += strlen(": ") +
592 u2_utflength(LLNI_field_direct(s, value)->data
593 + LLNI_field_direct(s, offset),
594 LLNI_field_direct(s,count));
598 logtextlen += strlen("(nil)");
601 /* allocate memory */
605 logtext = DMNEW(char, logtextlen);
607 strcpy(logtext, "Builtin exception thrown: ");
610 utf_cat_classname(logtext, xptr->vftbl->clazz->name);
615 buf = javastring_tochar((java_handle_t *) s);
616 strcat(logtext, ": ");
617 strcat(logtext, buf);
618 MFREE(buf, char, strlen(buf) + 1);
622 strcat(logtext, "(nil)");
632 #endif /* !defined(NDEBUG) */
638 * These are local overrides for various environment variables in Emacs.
639 * Please do not remove this and leave it at the end of the file, where
640 * Emacs will automagically detect them.
641 * ---------------------------------------------------------------------
644 * indent-tabs-mode: t
648 * vim:noexpandtab:sw=4:ts=4: