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.hpp"
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_handle_t*) (uintptr_t) 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 = (char*) DumpMemory::reallocate(logtext, *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 = (char*) DumpMemory::reallocate(logtext, *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)
205 /* We don't trace builtin functions here because the argument
206 passing happens via the native ABI and does not fit these
209 if (method_is_builtin(m))
212 #if defined(ENABLE_DEBUG_FILTER)
213 if (!show_filters_test_verbosecall_enter(m))
217 #if defined(ENABLE_VMLOG)
218 vmlog_cacao_enter_method(m);
224 /* calculate message length */
227 strlen("4294967295 ") +
228 strlen("-2147483647-") + /* INT_MAX should be sufficient */
229 TRACEJAVACALLINDENT +
231 ((m->clazz == NULL) ? strlen("NULL") : utf_bytes(m->clazz->name)) +
234 utf_bytes(m->descriptor);
236 /* Actually it's not possible to have all flags printed, but:
242 strlen(" PROTECTED") +
245 strlen(" SYNCHRONIZED") +
246 strlen(" VOLATILE") +
247 strlen(" TRANSIENT") +
249 strlen(" INTERFACE") +
250 strlen(" ABSTRACT") +
251 strlen(" METHOD_BUILTIN");
253 /* add maximal argument length */
257 strlen("-9223372036854775808 (0x123456789abcdef0), ") * md->paramcount +
261 // Create new dump memory area.
264 // TODO Use a std::string here.
265 logtext = (char*) DumpMemory::allocate(sizeof(char) * logtextlen);
267 TRACEJAVACALLCOUNT++;
269 sprintf(logtext, "%10d ", TRACEJAVACALLCOUNT);
270 sprintf(logtext + strlen(logtext), "-%d-", TRACEJAVACALLINDENT);
272 pos = strlen(logtext);
274 for (i = 0; i < TRACEJAVACALLINDENT; i++)
275 logtext[pos++] = '\t';
277 strcpy(logtext + pos, "called: ");
279 if (m->clazz != NULL)
280 utf_cat_classname(logtext, m->clazz->name);
282 strcat(logtext, "NULL");
283 strcat(logtext, ".");
284 utf_cat(logtext, m->name);
285 utf_cat(logtext, m->descriptor);
287 if (m->flags & ACC_PUBLIC) strcat(logtext, " PUBLIC");
288 if (m->flags & ACC_PRIVATE) strcat(logtext, " PRIVATE");
289 if (m->flags & ACC_PROTECTED) strcat(logtext, " PROTECTED");
290 if (m->flags & ACC_STATIC) strcat(logtext, " STATIC");
291 if (m->flags & ACC_FINAL) strcat(logtext, " FINAL");
292 if (m->flags & ACC_SYNCHRONIZED) strcat(logtext, " SYNCHRONIZED");
293 if (m->flags & ACC_VOLATILE) strcat(logtext, " VOLATILE");
294 if (m->flags & ACC_TRANSIENT) strcat(logtext, " TRANSIENT");
295 if (m->flags & ACC_NATIVE) strcat(logtext, " NATIVE");
296 if (m->flags & ACC_INTERFACE) strcat(logtext, " INTERFACE");
297 if (m->flags & ACC_ABSTRACT) strcat(logtext, " ABSTRACT");
299 strcat(logtext, "(");
301 for (i = 0; i < md->paramcount; ++i) {
302 arg = argument_jitarray_load(md, i, arg_regs, stack);
303 logtext = trace_java_call_print_argument(m, logtext, &logtextlen,
304 &md->paramtypes[i], arg);
305 if (i != (md->paramcount - 1)) {
306 strcat(logtext, ", ");
310 strcat(logtext, ")");
314 TRACEJAVACALLINDENT++;
317 /* trace_java_call_exit ********************************************************
319 Traces an exit form a java method.
321 return_regs: Array of size 1 containing return register.
322 The array is usually allocated on the stack and used for restoring the
325 *******************************************************************************/
327 void trace_java_call_exit(methodinfo *m, uint64_t *return_regs)
336 /* We don't trace builtin functions here because the argument
337 passing happens via the native ABI and does not fit these
340 if (method_is_builtin(m))
343 #if defined(ENABLE_DEBUG_FILTER)
344 if (!show_filters_test_verbosecall_exit(m))
348 #if defined(ENABLE_VMLOG)
349 vmlog_cacao_leave_method(m);
355 /* outdent the log message */
357 if (TRACEJAVACALLINDENT)
358 TRACEJAVACALLINDENT--;
360 log_text("trace_java_call_exit: WARNING: unmatched unindent");
362 /* calculate message length */
365 strlen("4294967295 ") +
366 strlen("-2147483647-") + /* INT_MAX should be sufficient */
367 TRACEJAVACALLINDENT +
368 strlen("finished: ") +
369 ((m->clazz == NULL) ? strlen("NULL") : utf_bytes(m->clazz->name)) +
372 utf_bytes(m->descriptor) +
373 strlen(" SYNCHRONIZED") + strlen("(") + strlen(")");
375 /* add maximal argument length */
377 logtextlen += strlen("->0.4872328470301428 (0x0123456789abcdef)");
379 // Create new dump memory area.
382 // TODO Use a std::string here.
383 logtext = (char*) DumpMemory::allocate(sizeof(char) * logtextlen);
385 /* generate the message */
387 sprintf(logtext, " ");
388 sprintf(logtext + strlen(logtext), "-%d-", TRACEJAVACALLINDENT);
390 pos = strlen(logtext);
392 for (i = 0; i < TRACEJAVACALLINDENT; i++)
393 logtext[pos++] = '\t';
395 strcpy(logtext + pos, "finished: ");
396 if (m->clazz != NULL)
397 utf_cat_classname(logtext, m->clazz->name);
399 strcat(logtext, "NULL");
400 strcat(logtext, ".");
401 utf_cat(logtext, m->name);
402 utf_cat(logtext, m->descriptor);
404 if (!IS_VOID_TYPE(md->returntype.type)) {
405 strcat(logtext, "->");
406 val = argument_jitreturn_load(md, return_regs);
409 trace_java_call_print_argument(m, logtext, &logtextlen,
410 &md->returntype, val);
417 /* trace_exception *************************************************************
419 Traces an exception which is handled by exceptions_handle_exception.
421 *******************************************************************************/
423 void trace_exception(java_object_t *xptr, methodinfo *m, void *pos)
429 /* calculate message length */
433 strlen("Exception ") + utf_bytes(xptr->vftbl->clazz->name);
436 logtextlen = strlen("Some Throwable");
439 logtextlen += strlen(" thrown in ");
443 utf_bytes(m->clazz->name) +
446 utf_bytes(m->descriptor) +
447 strlen("(NOSYNC,NATIVE");
449 #if SIZEOF_VOID_P == 8
451 strlen(")(0x123456789abcdef0) at position 0x123456789abcdef0 (");
453 logtextlen += strlen(")(0x12345678) at position 0x12345678 (");
456 if (m->clazz->sourcefile == NULL)
457 logtextlen += strlen("<NO CLASSFILE INFORMATION>");
459 logtextlen += utf_bytes(m->clazz->sourcefile);
461 logtextlen += strlen(":65536)");
465 logtextlen += strlen("call_java_method");
468 logtextlen += strlen("0");
470 // Create new dump memory area.
473 // TODO Use a std::string here.
474 logtext = (char*) DumpMemory::allocate(sizeof(char) * logtextlen);
477 strcpy(logtext, "Exception ");
478 utf_cat_classname(logtext, xptr->vftbl->clazz->name);
481 strcpy(logtext, "Some Throwable");
484 strcat(logtext, " thrown in ");
487 utf_cat_classname(logtext, m->clazz->name);
488 strcat(logtext, ".");
489 utf_cat(logtext, m->name);
490 utf_cat(logtext, m->descriptor);
492 if (m->flags & ACC_SYNCHRONIZED)
493 strcat(logtext, "(SYNC");
495 strcat(logtext, "(NOSYNC");
497 if (m->flags & ACC_NATIVE) {
498 strcat(logtext, ",NATIVE");
502 #if SIZEOF_VOID_P == 8
503 sprintf(logtext + strlen(logtext),
504 ")(0x%016lx) at position 0x%016lx",
505 (ptrint) code->entrypoint, (ptrint) pos);
507 sprintf(logtext + strlen(logtext),
508 ")(0x%08x) at position 0x%08x",
509 (ptrint) code->entrypoint, (ptrint) pos);
514 /* XXX preliminary: This should get the actual codeinfo */
515 /* in which the exception happened. */
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);
528 if (m->clazz->sourcefile == NULL)
529 strcat(logtext, "<NO CLASSFILE INFORMATION>");
531 utf_cat(logtext, m->clazz->sourcefile);
533 sprintf(logtext + strlen(logtext), ":%d)", 0);
537 strcat(logtext, "call_java_method");
543 /* trace_exception_builtin *****************************************************
545 Traces an exception which is thrown by builtin_throw_exception.
547 *******************************************************************************/
549 void trace_exception_builtin(java_handle_t* h)
554 java_lang_Throwable jlt(h);
556 // Get detail message.
557 java_handle_t* s = NULL;
559 if (jlt.get_handle() != NULL)
560 s = jlt.get_detailMessage();
562 java_lang_String jls(s);
564 /* calculate message length */
566 logtextlen = strlen("Builtin exception thrown: ") + strlen("0");
568 if (jlt.get_handle() != NULL) {
569 logtextlen += utf_bytes(jlt.get_vftbl()->clazz->name);
571 if (jls.get_handle()) {
572 // FIXME This is not handle capable!
573 logtextlen += strlen(": ") +
574 u2_utflength(jls.get_value()->data + jls.get_offset(), jls.get_count());
578 logtextlen += strlen("(nil)");
581 // Create new dump memory area.
584 logtext = (char*) DumpMemory::allocate(sizeof(char) * logtextlen);
586 strcpy(logtext, "Builtin exception thrown: ");
588 if (jlt.get_handle()) {
589 utf_cat_classname(logtext, jlt.get_vftbl()->clazz->name);
594 buf = javastring_tochar(jls.get_handle());
595 strcat(logtext, ": ");
596 strcat(logtext, buf);
597 MFREE(buf, char, strlen(buf) + 1);
601 strcat(logtext, "(nil)");
609 #endif /* !defined(NDEBUG) */
613 * These are local overrides for various environment variables in Emacs.
614 * Please do not remove this and leave it at the end of the file, where
615 * Emacs will automagically detect them.
616 * ---------------------------------------------------------------------
619 * indent-tabs-mode: t
623 * vim:noexpandtab:sw=4:ts=4: