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
33 #include "mm/memory.h"
35 #include "native/llni.h"
37 #include "threads/thread.hpp"
39 #include "toolbox/logging.h"
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"
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"
56 // FIXME For now we export everything as C functions.
59 /* global variables ***********************************************************/
61 #if !defined(ENABLE_THREADS)
62 s4 _no_threads_tracejavacallindent = 0;
63 u4 _no_threads_tracejavacallcount= 0;
67 /* trace_java_call_print_argument **********************************************
71 *******************************************************************************/
73 static char *trace_java_call_print_argument(methodinfo *m, char *logtext, s4 *logtextlen, typedesc *paramtype, imm_union imu)
80 switch (paramtype->type) {
82 sprintf(logtext + strlen(logtext), "%d (0x%08x)", (int32_t)imu.l, (int32_t)imu.l);
86 #if SIZEOF_VOID_P == 4
87 sprintf(logtext + strlen(logtext), "%lld (0x%016llx)", imu.l, imu.l);
89 sprintf(logtext + strlen(logtext), "%ld (0x%016lx)", imu.l, imu.l);
94 sprintf(logtext + strlen(logtext), "%g (0x%08x)", imu.f, imu.i);
98 #if SIZEOF_VOID_P == 4
99 sprintf(logtext + strlen(logtext), "%g (0x%016llx)", imu.d, imu.l);
101 sprintf(logtext + strlen(logtext), "%g (0x%016lx)", imu.d, imu.l);
106 #if SIZEOF_VOID_P == 4
107 sprintf(logtext + strlen(logtext), "0x%08x", (ptrint) imu.l);
109 sprintf(logtext + strlen(logtext), "0x%016lx", (ptrint) imu.l);
112 /* Workaround for sun.misc.Unsafe methods. In the future
113 (exact GC) we should check if the address is on the GC
116 if ((m->clazz != NULL) &&
117 (m->clazz->name == utf_new_char("sun/misc/Unsafe")))
120 /* Cast to java.lang.Object. */
122 o = (java_object_t *) (ptrint) imu.l;
124 /* Check return argument for java.lang.Class or
128 if (o->vftbl->clazz == class_java_lang_String) {
129 /* get java.lang.String object and the length of the
132 u = javastring_toutf(o, false);
134 len = strlen(" (String = \"") + utf_bytes(u) + strlen("\")");
136 /* realloc memory for string length */
138 logtext = DMREALLOC(logtext, char, *logtextlen, *logtextlen + len);
141 /* convert to utf8 string and strcat it to the logtext */
143 strcat(logtext, " (String = \"");
145 strcat(logtext, "\")");
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
158 /* if the object returned is not a java.lang.String or
159 a java.lang.Class just print the name of the class */
161 u = o->vftbl->clazz->name;
164 len = strlen(" (Class = \"") + utf_bytes(u) + strlen("\")");
166 /* realloc memory for string length */
168 logtext = DMREALLOC(logtext, char, *logtextlen, *logtextlen + len);
171 /* strcat to the logtext */
173 strcat(logtext, " (Class = \"");
174 utf_cat_classname(logtext, u);
175 strcat(logtext, "\")");
183 /* trace_java_call_enter ******************************************************
185 Traces an entry into a java method.
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.
191 stack: Pointer to first on stack argument in the same format passed to
194 *******************************************************************************/
196 void trace_java_call_enter(methodinfo *m, uint64_t *arg_regs, uint64_t *stack)
206 /* We don't trace builtin functions here because the argument
207 passing happens via the native ABI and does not fit these
210 if (method_is_builtin(m))
213 #if defined(ENABLE_DEBUG_FILTER)
214 if (!show_filters_test_verbosecall_enter(m))
218 #if defined(ENABLE_VMLOG)
219 vmlog_cacao_enter_method(m);
225 /* calculate message length */
228 strlen("4294967295 ") +
229 strlen("-2147483647-") + /* INT_MAX should be sufficient */
230 TRACEJAVACALLINDENT +
232 ((m->clazz == NULL) ? strlen("NULL") : utf_bytes(m->clazz->name)) +
235 utf_bytes(m->descriptor);
237 /* Actually it's not possible to have all flags printed, but:
243 strlen(" PROTECTED") +
246 strlen(" SYNCHRONIZED") +
247 strlen(" VOLATILE") +
248 strlen(" TRANSIENT") +
250 strlen(" INTERFACE") +
251 strlen(" ABSTRACT") +
252 strlen(" METHOD_BUILTIN");
254 /* add maximal argument length */
258 strlen("-9223372036854775808 (0x123456789abcdef0), ") * md->paramcount +
262 /* allocate memory */
266 logtext = DMNEW(char, logtextlen);
268 TRACEJAVACALLCOUNT++;
270 sprintf(logtext, "%10d ", TRACEJAVACALLCOUNT);
271 sprintf(logtext + strlen(logtext), "-%d-", TRACEJAVACALLINDENT);
273 pos = strlen(logtext);
275 for (i = 0; i < TRACEJAVACALLINDENT; i++)
276 logtext[pos++] = '\t';
278 strcpy(logtext + pos, "called: ");
280 if (m->clazz != NULL)
281 utf_cat_classname(logtext, m->clazz->name);
283 strcat(logtext, "NULL");
284 strcat(logtext, ".");
285 utf_cat(logtext, m->name);
286 utf_cat(logtext, m->descriptor);
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");
300 strcat(logtext, "(");
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, ", ");
311 strcat(logtext, ")");
319 TRACEJAVACALLINDENT++;
323 /* trace_java_call_exit ********************************************************
325 Traces an exit form a java method.
327 return_regs: Array of size 1 containing return register.
328 The array is usually allocated on the stack and used for restoring the
331 *******************************************************************************/
333 void trace_java_call_exit(methodinfo *m, uint64_t *return_regs)
343 /* We don't trace builtin functions here because the argument
344 passing happens via the native ABI and does not fit these
347 if (method_is_builtin(m))
350 #if defined(ENABLE_DEBUG_FILTER)
351 if (!show_filters_test_verbosecall_exit(m))
355 #if defined(ENABLE_VMLOG)
356 vmlog_cacao_leave_method(m);
362 /* outdent the log message */
364 if (TRACEJAVACALLINDENT)
365 TRACEJAVACALLINDENT--;
367 log_text("trace_java_call_exit: WARNING: unmatched unindent");
369 /* calculate message length */
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)) +
379 utf_bytes(m->descriptor) +
380 strlen(" SYNCHRONIZED") + strlen("(") + strlen(")");
382 /* add maximal argument length */
384 logtextlen += strlen("->0.4872328470301428 (0x0123456789abcdef)");
386 /* allocate memory */
390 logtext = DMNEW(char, logtextlen);
392 /* generate the message */
394 sprintf(logtext, " ");
395 sprintf(logtext + strlen(logtext), "-%d-", TRACEJAVACALLINDENT);
397 pos = strlen(logtext);
399 for (i = 0; i < TRACEJAVACALLINDENT; i++)
400 logtext[pos++] = '\t';
402 strcpy(logtext + pos, "finished: ");
403 if (m->clazz != NULL)
404 utf_cat_classname(logtext, m->clazz->name);
406 strcat(logtext, "NULL");
407 strcat(logtext, ".");
408 utf_cat(logtext, m->name);
409 utf_cat(logtext, m->descriptor);
411 if (!IS_VOID_TYPE(md->returntype.type)) {
412 strcat(logtext, "->");
413 val = argument_jitreturn_load(md, return_regs);
416 trace_java_call_print_argument(m, logtext, &logtextlen,
417 &md->returntype, val);
428 /* trace_exception *************************************************************
430 Traces an exception which is handled by exceptions_handle_exception.
432 *******************************************************************************/
434 void trace_exception(java_object_t *xptr, methodinfo *m, void *pos)
441 /* calculate message length */
445 strlen("Exception ") + utf_bytes(xptr->vftbl->clazz->name);
448 logtextlen = strlen("Some Throwable");
451 logtextlen += strlen(" thrown in ");
455 utf_bytes(m->clazz->name) +
458 utf_bytes(m->descriptor) +
459 strlen("(NOSYNC,NATIVE");
461 #if SIZEOF_VOID_P == 8
463 strlen(")(0x123456789abcdef0) at position 0x123456789abcdef0 (");
465 logtextlen += strlen(")(0x12345678) at position 0x12345678 (");
468 if (m->clazz->sourcefile == NULL)
469 logtextlen += strlen("<NO CLASSFILE INFORMATION>");
471 logtextlen += utf_bytes(m->clazz->sourcefile);
473 logtextlen += strlen(":65536)");
477 logtextlen += strlen("call_java_method");
480 logtextlen += strlen("0");
482 /* allocate memory */
486 logtext = DMNEW(char, logtextlen);
489 strcpy(logtext, "Exception ");
490 utf_cat_classname(logtext, xptr->vftbl->clazz->name);
493 strcpy(logtext, "Some Throwable");
496 strcat(logtext, " thrown in ");
499 utf_cat_classname(logtext, m->clazz->name);
500 strcat(logtext, ".");
501 utf_cat(logtext, m->name);
502 utf_cat(logtext, m->descriptor);
504 if (m->flags & ACC_SYNCHRONIZED)
505 strcat(logtext, "(SYNC");
507 strcat(logtext, "(NOSYNC");
509 if (m->flags & ACC_NATIVE) {
510 strcat(logtext, ",NATIVE");
514 #if SIZEOF_VOID_P == 8
515 sprintf(logtext + strlen(logtext),
516 ")(0x%016lx) at position 0x%016lx",
517 (ptrint) code->entrypoint, (ptrint) pos);
519 sprintf(logtext + strlen(logtext),
520 ")(0x%08x) at position 0x%08x",
521 (ptrint) code->entrypoint, (ptrint) pos);
526 /* XXX preliminary: This should get the actual codeinfo */
527 /* in which the exception happened. */
530 #if SIZEOF_VOID_P == 8
531 sprintf(logtext + strlen(logtext),
532 ")(0x%016lx) at position 0x%016lx (",
533 (ptrint) code->entrypoint, (ptrint) pos);
535 sprintf(logtext + strlen(logtext),
536 ")(0x%08x) at position 0x%08x (",
537 (ptrint) code->entrypoint, (ptrint) pos);
540 if (m->clazz->sourcefile == NULL)
541 strcat(logtext, "<NO CLASSFILE INFORMATION>");
543 utf_cat(logtext, m->clazz->sourcefile);
545 sprintf(logtext + strlen(logtext), ":%d)", 0);
549 strcat(logtext, "call_java_method");
559 /* trace_exception_builtin *****************************************************
561 Traces an exception which is thrown by builtin_throw_exception.
563 *******************************************************************************/
565 void trace_exception_builtin(java_handle_t* h)
571 java_lang_Throwable jlt(h);
573 // Get detail message.
574 java_handle_t* s = NULL;
576 if (jlt.get_handle() != NULL)
577 s = jlt.get_detailMessage();
579 java_lang_String jls(s);
581 /* calculate message length */
583 logtextlen = strlen("Builtin exception thrown: ") + strlen("0");
585 if (jlt.get_handle() != NULL) {
586 logtextlen += utf_bytes(jlt.get_vftbl()->clazz->name);
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());
595 logtextlen += strlen("(nil)");
598 /* allocate memory */
602 logtext = DMNEW(char, logtextlen);
604 strcpy(logtext, "Builtin exception thrown: ");
606 if (jlt.get_handle()) {
607 utf_cat_classname(logtext, jlt.get_vftbl()->clazz->name);
612 buf = javastring_tochar(jls.get_handle());
613 strcat(logtext, ": ");
614 strcat(logtext, buf);
615 MFREE(buf, char, strlen(buf) + 1);
619 strcat(logtext, "(nil)");
631 #endif /* !defined(NDEBUG) */
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 * ---------------------------------------------------------------------
641 * indent-tabs-mode: t
645 * vim:noexpandtab:sw=4:ts=4: