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.hpp"
35 #include "native/llni.h"
37 #include "threads/thread.hpp"
39 #include "toolbox/logging.hpp"
41 #include "vm/array.hpp"
42 #include "vm/global.h"
43 #include "vm/globals.hpp"
44 #include "vm/hook.hpp"
45 #include "vm/javaobjects.hpp"
46 #include "vm/options.h"
47 #include "vm/string.hpp"
50 #include "vm/jit/argument.hpp"
51 #include "vm/jit/codegen-common.hpp"
52 #include "vm/jit/trace.hpp"
53 #include "vm/jit/show.hpp"
58 // FIXME For now we export everything as C functions.
61 /* global variables ***********************************************************/
63 #if !defined(ENABLE_THREADS)
64 s4 _no_threads_tracejavacallindent = 0;
65 u4 _no_threads_tracejavacallcount= 0;
69 /* trace_java_call_print_argument **********************************************
73 *******************************************************************************/
75 static char *trace_java_call_print_argument(methodinfo *m, char *logtext, s4 *logtextlen, typedesc *paramtype, imm_union imu)
82 switch (paramtype->type) {
84 sprintf(logtext + strlen(logtext), "%d (0x%08x)", (int32_t)imu.l, (int32_t)imu.l);
88 #if SIZEOF_VOID_P == 4
89 sprintf(logtext + strlen(logtext), "%lld (0x%016llx)", imu.l, imu.l);
91 sprintf(logtext + strlen(logtext), "%ld (0x%016lx)", imu.l, imu.l);
96 sprintf(logtext + strlen(logtext), "%g (0x%08x)", imu.f, imu.i);
100 #if SIZEOF_VOID_P == 4
101 sprintf(logtext + strlen(logtext), "%g (0x%016llx)", imu.d, imu.l);
103 sprintf(logtext + strlen(logtext), "%g (0x%016lx)", imu.d, imu.l);
108 #if SIZEOF_VOID_P == 4
109 sprintf(logtext + strlen(logtext), "0x%08x", (ptrint) imu.l);
111 sprintf(logtext + strlen(logtext), "0x%016lx", (ptrint) imu.l);
114 /* Workaround for sun.misc.Unsafe methods. In the future
115 (exact GC) we should check if the address is on the GC
118 if ((m->clazz != NULL) &&
119 (m->clazz->name == utf_new_char("sun/misc/Unsafe")))
122 /* Cast to java.lang.Object. */
124 o = (java_handle_t*) (uintptr_t) imu.l;
126 /* Check return argument for java.lang.Class or
130 if (o->vftbl->clazz == class_java_lang_String) {
131 /* get java.lang.String object and the length of the
134 u = javastring_toutf(o, false);
136 len = strlen(" (String = \"") + utf_bytes(u) + strlen("\")");
138 /* realloc memory for string length */
140 logtext = (char*) DumpMemory::reallocate(logtext, *logtextlen, *logtextlen + len);
143 /* convert to utf8 string and strcat it to the logtext */
145 strcat(logtext, " (String = \"");
147 strcat(logtext, "\")");
150 if (o->vftbl->clazz == class_java_lang_Class) {
151 /* if the object returned is a java.lang.Class
152 cast it to classinfo structure and get the name
160 /* if the object returned is not a java.lang.String or
161 a java.lang.Class just print the name of the class */
163 u = o->vftbl->clazz->name;
166 len = strlen(" (Class = \"") + utf_bytes(u) + strlen("\")");
168 /* realloc memory for string length */
170 logtext = (char*) DumpMemory::reallocate(logtext, *logtextlen, *logtextlen + len);
173 /* strcat to the logtext */
175 strcat(logtext, " (Class = \"");
176 utf_cat_classname(logtext, u);
177 strcat(logtext, "\")");
185 /* trace_java_call_enter ******************************************************
187 Traces an entry into a java method.
189 arg_regs: Array containing all argument registers as int64_t values in
190 the same order as listed in m->methoddesc. The array is usually allocated
191 on the stack and used for restoring the argument registers later.
193 stack: Pointer to first on stack argument in the same format passed to
196 *******************************************************************************/
198 void trace_java_call_enter(methodinfo *m, uint64_t *arg_regs, uint64_t *stack)
207 /* We can only trace "slow" builtin functions (those with a stub)
208 * here, because the argument passing of "fast" ones happens via
209 * the native ABI and does not fit these functions. */
211 if (method_is_builtin(m)) {
212 if (!opt_TraceBuiltinCalls)
216 if (!opt_TraceJavaCalls)
218 #if defined(ENABLE_DEBUG_FILTER)
219 if (!show_filters_test_verbosecall_enter(m))
224 #if defined(ENABLE_VMLOG)
225 vmlog_cacao_enter_method(m);
229 // Hook point on entry into Java method.
230 Hook::method_enter(m);
234 /* calculate message length */
237 strlen("4294967295 ") +
238 strlen("-2147483647-") + /* INT_MAX should be sufficient */
239 TRACEJAVACALLINDENT +
241 ((m->clazz == NULL) ? strlen("NULL") : utf_bytes(m->clazz->name)) +
244 utf_bytes(m->descriptor);
246 /* Actually it's not possible to have all flags printed, but:
252 strlen(" PROTECTED") +
255 strlen(" SYNCHRONIZED") +
256 strlen(" VOLATILE") +
257 strlen(" TRANSIENT") +
259 strlen(" INTERFACE") +
260 strlen(" ABSTRACT") +
261 strlen(" METHOD_BUILTIN");
263 /* add maximal argument length */
267 strlen("-9223372036854775808 (0x123456789abcdef0), ") * md->paramcount +
271 // Create new dump memory area.
274 // TODO Use a std::string here.
275 logtext = (char*) DumpMemory::allocate(sizeof(char) * logtextlen);
277 TRACEJAVACALLCOUNT++;
279 sprintf(logtext, "%10d ", TRACEJAVACALLCOUNT);
280 sprintf(logtext + strlen(logtext), "-%d-", TRACEJAVACALLINDENT);
282 pos = strlen(logtext);
284 for (i = 0; i < TRACEJAVACALLINDENT; i++)
285 logtext[pos++] = '\t';
287 strcpy(logtext + pos, "called: ");
289 if (m->clazz != NULL)
290 utf_cat_classname(logtext, m->clazz->name);
292 strcat(logtext, "NULL");
293 strcat(logtext, ".");
294 utf_cat(logtext, m->name);
295 utf_cat(logtext, m->descriptor);
297 if (m->flags & ACC_PUBLIC) strcat(logtext, " PUBLIC");
298 if (m->flags & ACC_PRIVATE) strcat(logtext, " PRIVATE");
299 if (m->flags & ACC_PROTECTED) strcat(logtext, " PROTECTED");
300 if (m->flags & ACC_STATIC) strcat(logtext, " STATIC");
301 if (m->flags & ACC_FINAL) strcat(logtext, " FINAL");
302 if (m->flags & ACC_SYNCHRONIZED) strcat(logtext, " SYNCHRONIZED");
303 if (m->flags & ACC_VOLATILE) strcat(logtext, " VOLATILE");
304 if (m->flags & ACC_TRANSIENT) strcat(logtext, " TRANSIENT");
305 if (m->flags & ACC_NATIVE) strcat(logtext, " NATIVE");
306 if (m->flags & ACC_INTERFACE) strcat(logtext, " INTERFACE");
307 if (m->flags & ACC_ABSTRACT) strcat(logtext, " ABSTRACT");
309 strcat(logtext, "(");
311 for (i = 0; i < md->paramcount; ++i) {
312 arg = argument_jitarray_load(md, i, arg_regs, stack);
313 logtext = trace_java_call_print_argument(m, logtext, &logtextlen,
314 &md->paramtypes[i], arg);
315 if (i != (md->paramcount - 1)) {
316 strcat(logtext, ", ");
320 strcat(logtext, ")");
324 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)
346 /* We can only trace "slow" builtin functions (those with a stub)
347 * here, because the argument passing of "fast" ones happens via
348 * the native ABI and does not fit these functions. */
350 if (method_is_builtin(m)) {
351 if (!opt_TraceBuiltinCalls)
355 if (!opt_TraceJavaCalls)
357 #if defined(ENABLE_DEBUG_FILTER)
358 if (!show_filters_test_verbosecall_exit(m))
363 #if defined(ENABLE_VMLOG)
364 vmlog_cacao_leave_method(m);
368 // Hook point upon exit from Java method.
369 Hook::method_exit(m);
373 /* outdent the log message */
375 if (TRACEJAVACALLINDENT)
376 TRACEJAVACALLINDENT--;
378 log_text("trace_java_call_exit: WARNING: unmatched unindent");
380 /* calculate message length */
383 strlen("4294967295 ") +
384 strlen("-2147483647-") + /* INT_MAX should be sufficient */
385 TRACEJAVACALLINDENT +
386 strlen("finished: ") +
387 ((m->clazz == NULL) ? strlen("NULL") : utf_bytes(m->clazz->name)) +
390 utf_bytes(m->descriptor) +
391 strlen(" SYNCHRONIZED") + strlen("(") + strlen(")");
393 /* add maximal argument length */
395 logtextlen += strlen("->0.4872328470301428 (0x0123456789abcdef)");
397 // Create new dump memory area.
400 // TODO Use a std::string here.
401 logtext = (char*) DumpMemory::allocate(sizeof(char) * logtextlen);
403 /* generate the message */
405 sprintf(logtext, " ");
406 sprintf(logtext + strlen(logtext), "-%d-", TRACEJAVACALLINDENT);
408 pos = strlen(logtext);
410 for (i = 0; i < TRACEJAVACALLINDENT; i++)
411 logtext[pos++] = '\t';
413 strcpy(logtext + pos, "finished: ");
414 if (m->clazz != NULL)
415 utf_cat_classname(logtext, m->clazz->name);
417 strcat(logtext, "NULL");
418 strcat(logtext, ".");
419 utf_cat(logtext, m->name);
420 utf_cat(logtext, m->descriptor);
422 if (!IS_VOID_TYPE(md->returntype.type)) {
423 strcat(logtext, "->");
424 val = argument_jitreturn_load(md, return_regs);
427 trace_java_call_print_argument(m, logtext, &logtextlen,
428 &md->returntype, val);
435 /* trace_exception *************************************************************
437 Traces an exception which is handled by exceptions_handle_exception.
439 *******************************************************************************/
441 void trace_exception(java_object_t *xptr, methodinfo *m, void *pos)
447 /* calculate message length */
451 strlen("Exception ") + utf_bytes(xptr->vftbl->clazz->name);
454 logtextlen = strlen("Some Throwable");
457 logtextlen += strlen(" thrown in ");
461 utf_bytes(m->clazz->name) +
464 utf_bytes(m->descriptor) +
465 strlen("(NOSYNC,NATIVE");
467 #if SIZEOF_VOID_P == 8
469 strlen(")(0x123456789abcdef0) at position 0x123456789abcdef0 (");
471 logtextlen += strlen(")(0x12345678) at position 0x12345678 (");
474 if (m->clazz->sourcefile == NULL)
475 logtextlen += strlen("<NO CLASSFILE INFORMATION>");
477 logtextlen += utf_bytes(m->clazz->sourcefile);
479 logtextlen += strlen(":65536)");
483 logtextlen += strlen("call_java_method");
486 logtextlen += strlen("0");
488 // Create new dump memory area.
491 // TODO Use a std::string here.
492 logtext = (char*) DumpMemory::allocate(sizeof(char) * logtextlen);
495 strcpy(logtext, "Exception ");
496 utf_cat_classname(logtext, xptr->vftbl->clazz->name);
499 strcpy(logtext, "Some Throwable");
502 strcat(logtext, " thrown in ");
505 utf_cat_classname(logtext, m->clazz->name);
506 strcat(logtext, ".");
507 utf_cat(logtext, m->name);
508 utf_cat(logtext, m->descriptor);
510 if (m->flags & ACC_SYNCHRONIZED)
511 strcat(logtext, "(SYNC");
513 strcat(logtext, "(NOSYNC");
515 if (m->flags & ACC_NATIVE) {
516 strcat(logtext, ",NATIVE");
520 #if SIZEOF_VOID_P == 8
521 sprintf(logtext + strlen(logtext),
522 ")(0x%016lx) at position 0x%016lx",
523 (ptrint) code->entrypoint, (ptrint) pos);
525 sprintf(logtext + strlen(logtext),
526 ")(0x%08x) at position 0x%08x",
527 (ptrint) code->entrypoint, (ptrint) pos);
532 /* XXX preliminary: This should get the actual codeinfo */
533 /* in which the exception happened. */
536 #if SIZEOF_VOID_P == 8
537 sprintf(logtext + strlen(logtext),
538 ")(0x%016lx) at position 0x%016lx (",
539 (ptrint) code->entrypoint, (ptrint) pos);
541 sprintf(logtext + strlen(logtext),
542 ")(0x%08x) at position 0x%08x (",
543 (ptrint) code->entrypoint, (ptrint) pos);
546 if (m->clazz->sourcefile == NULL)
547 strcat(logtext, "<NO CLASSFILE INFORMATION>");
549 utf_cat(logtext, m->clazz->sourcefile);
551 sprintf(logtext + strlen(logtext), ":%d)", 0);
555 strcat(logtext, "call_java_method");
561 /* trace_exception_builtin *****************************************************
563 Traces an exception which is thrown by builtin_throw_exception.
565 *******************************************************************************/
567 void trace_exception_builtin(java_handle_t* h)
572 java_lang_Throwable jlt(h);
574 // Get detail message.
575 java_handle_t* s = NULL;
577 if (jlt.get_handle() != NULL)
578 s = jlt.get_detailMessage();
580 java_lang_String jls(s);
582 /* calculate message length */
584 logtextlen = strlen("Builtin exception thrown: ") + strlen("0");
586 if (jlt.get_handle() != NULL) {
587 logtextlen += utf_bytes(jlt.get_vftbl()->clazz->name);
589 if (jls.get_handle()) {
590 CharArray ca(jls.get_value());
591 // FIXME This is not handle capable!
592 uint16_t* ptr = (uint16_t*) ca.get_raw_data_ptr();
593 logtextlen += strlen(": ") +
594 u2_utflength(ptr + jls.get_offset(), jls.get_count());
598 logtextlen += strlen("(nil)");
601 // Create new dump memory area.
604 logtext = (char*) DumpMemory::allocate(sizeof(char) * logtextlen);
606 strcpy(logtext, "Builtin exception thrown: ");
608 if (jlt.get_handle()) {
609 utf_cat_classname(logtext, jlt.get_vftbl()->clazz->name);
614 buf = javastring_tochar(jls.get_handle());
615 strcat(logtext, ": ");
616 strcat(logtext, buf);
617 MFREE(buf, char, strlen(buf) + 1);
621 strcat(logtext, "(nil)");
629 #endif /* !defined(NDEBUG) */
633 * These are local overrides for various environment variables in Emacs.
634 * Please do not remove this and leave it at the end of the file, where
635 * Emacs will automagically detect them.
636 * ---------------------------------------------------------------------
639 * indent-tabs-mode: t
643 * vim:noexpandtab:sw=4:ts=4: