Each thread has its own trace buffer to which strings are printed with
trace_pritnf(). When trace_flush() is called the buffer's content is
printed to stderr. trace_flush() is synchronized with other threads.

if -Xtrace:threads is passed to jato, every line of trace will be
printed with trailing current thread's name.

Signed-off-by: Tomek Grabiec <tgrab...@gmail.com>
---
 Makefile               |    1 +
 arch/x86/backtrace.c   |    3 +
 arch/x86/disassemble.c |   12 ++-
 include/jit/compiler.h |    4 +-
 include/vm/trace.h     |    7 ++
 jit/compiler.c         |    4 +
 jit/exception.c        |   11 +-
 jit/trace-jit.c        |  239 ++++++++++++++++++++++--------------------------
 test/arch-x86/Makefile |    1 +
 test/jit/Makefile      |    2 +
 test/jit/trace-stub.c  |    1 +
 test/vm/Makefile       |    5 +-
 test/vm/thread-stub.c  |    8 ++
 vm/bytecodes.c         |   17 ++--
 vm/classloader.c       |    8 +-
 vm/jato.c              |    9 ++
 vm/stack-trace.c       |   25 +++--
 vm/trace.c             |  101 ++++++++++++++++++++
 18 files changed, 293 insertions(+), 165 deletions(-)
 create mode 100644 include/vm/trace.h
 create mode 100644 test/vm/thread-stub.c
 create mode 100644 vm/trace.c

diff --git a/Makefile b/Makefile
index c037fb8..1cdc587 100644
--- a/Makefile
+++ b/Makefile
@@ -114,6 +114,7 @@ VM_OBJS = \
        vm/stack-trace.o        \
        vm/static.o             \
        vm/thread.o             \
+       vm/trace.o              \
        vm/types.o              \
        vm/utf8.o               \
        vm/zalloc.o             \
diff --git a/arch/x86/backtrace.c b/arch/x86/backtrace.c
index aaa0615..64e5ccd 100644
--- a/arch/x86/backtrace.c
+++ b/arch/x86/backtrace.c
@@ -38,6 +38,7 @@
 #include "vm/class.h"
 #include "vm/method.h"
 #include "vm/stack-trace.h"
+#include "vm/trace.h"
 
 /* get REG_EIP from ucontext.h */
 #include <ucontext.h>
@@ -241,5 +242,7 @@ void print_backtrace_and_die(int sig, siginfo_t *info, void 
*secret)
 
        print_trace_from(eip, (void *) ebp);
 
+       trace_flush();
+
        exit(1);
 }
diff --git a/arch/x86/disassemble.c b/arch/x86/disassemble.c
index 67ae90b..095ebac 100644
--- a/arch/x86/disassemble.c
+++ b/arch/x86/disassemble.c
@@ -36,6 +36,8 @@
 #include "jit/compiler.h"
 #include "lib/string.h"
 
+#include "vm/trace.h"
+
 #include <assert.h>
 #include <dis-asm.h>
 #include <stdarg.h>
@@ -84,25 +86,25 @@ unsigned char *disassinstr(struct compilation_unit *cu, 
unsigned char *code)
 
                bc_offset = native_ptr_to_bytecode_offset(cu, code);
                print_bytecode_offset(bc_offset, str);
-               printf("[ %5s ]", str->value);
+               trace_printf("[ %5s ]", str->value);
                free_str(str);
        }
 
-       printf("  0x%08lx:   ", (unsigned long) code);
+       trace_printf("  0x%08lx:   ", (unsigned long) code);
 
        disass_len = 0;
 
        seqlen = print_insn_i386((bfd_vma) (unsigned long) code, &info);
 
        for (i = 0; i < seqlen; i++, code++) {
-               printf("%02x ", *code);
+               trace_printf("%02x ", *code);
        }
 
        for (; i < 8; i++) {
-               printf("   ");
+               trace_printf("   ");
        }
 
-       printf("   %s\n", disass_buf);
+       trace_printf("   %s\n", disass_buf);
 
        return code;
 }
diff --git a/include/jit/compiler.h b/include/jit/compiler.h
index a781730..087a795 100644
--- a/include/jit/compiler.h
+++ b/include/jit/compiler.h
@@ -101,6 +101,8 @@ extern bool opt_trace_invoke;
 extern bool opt_trace_invoke_verbose;
 extern bool opt_trace_exceptions;
 extern bool opt_trace_bytecode;
+extern bool opt_trace_compile;
+extern bool opt_trace_threads;
 
 void trace_magic_trampoline(struct compilation_unit *);
 void trace_method(struct compilation_unit *);
@@ -116,7 +118,5 @@ void trace_exception_handler(struct compilation_unit *, 
unsigned char *);
 void trace_exception_unwind(struct jit_stack_frame *);
 void trace_exception_unwind_to_native(struct jit_stack_frame *);
 void trace_bytecode(struct vm_method *);
-void trace_begin(void);
-void trace_end(void);
 
 #endif
diff --git a/include/vm/trace.h b/include/vm/trace.h
new file mode 100644
index 0000000..79959ea
--- /dev/null
+++ b/include/vm/trace.h
@@ -0,0 +1,7 @@
+#ifndef _VM_TRACE_H
+#define _VM_TRACE_H
+
+int trace_printf(const char *fmt, ...);
+void trace_flush(void);
+
+#endif /* _VM_TRACE_H */
diff --git a/jit/compiler.c b/jit/compiler.c
index fa3deaa..e88dd55 100644
--- a/jit/compiler.c
+++ b/jit/compiler.c
@@ -17,6 +17,7 @@
 
 #include "vm/class.h"
 #include "vm/method.h"
+#include "vm/trace.h"
 
 #include <errno.h>
 #include <stdlib.h>
@@ -120,6 +121,9 @@ int compile(struct compilation_unit *cu)
 
        perf_append_cu(cu);
   out:
+       if (opt_trace_compile)
+               trace_flush();
+
        if (err)
                compile_error(cu, err);
        return err;
diff --git a/jit/exception.c b/jit/exception.c
index c5a7160..13f4800 100644
--- a/jit/exception.c
+++ b/jit/exception.c
@@ -43,6 +43,7 @@
 #include "vm/object.h"
 #include "vm/preload.h"
 #include "vm/thread.h"
+#include "vm/trace.h"
 
 #include "arch/stack-frame.h"
 #include "arch/instruction.h"
@@ -317,21 +318,21 @@ print_exception_table(const struct vm_method *method,
        int exception_table_length)
 {
        if (exception_table_length == 0) {
-               printf("\t(empty)\n");
+               trace_printf("\t(empty)\n");
                return;
        }
 
-       printf("\tfrom\tto\ttarget\ttype\n");
+       trace_printf("\tfrom\tto\ttarget\ttype\n");
        for (int i = 0; i < exception_table_length; i++) {
                const struct cafebabe_code_attribute_exception *eh;
 
                eh = &exception_table[i];
 
-               printf("\t%d\t%d\t%d\t", eh->start_pc, eh->end_pc,
+               trace_printf("\t%d\t%d\t%d\t", eh->start_pc, eh->end_pc,
                       eh->handler_pc);
 
                if (!eh->catch_type) {
-                       printf("all\n");
+                       trace_printf("all\n");
                        return;
                }
 
@@ -339,6 +340,6 @@ print_exception_table(const struct vm_method *method,
                catch_class = vm_class_resolve_class(method->class,
                                                     eh->catch_type);
 
-               printf("Class %s\n", catch_class->name);
+               trace_printf("Class %s\n", catch_class->name);
        }
 }
diff --git a/jit/trace-jit.c b/jit/trace-jit.c
index 37fe6d4..8a3eaa9 100644
--- a/jit/trace-jit.c
+++ b/jit/trace-jit.c
@@ -20,6 +20,7 @@
 #include "vm/preload.h"
 #include "vm/object.h"
 #include "vm/bytecodes.h"
+#include "vm/trace.h"
 
 #include "lib/buffer.h"
 #include "vm/class.h"
@@ -47,39 +48,8 @@ bool opt_trace_invoke;
 bool opt_trace_invoke_verbose;
 bool opt_trace_exceptions;
 bool opt_trace_bytecode;
-
-static pthread_mutex_t trace_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void print_current_thread(void)
-{
-       struct vm_object *thread;
-       struct vm_object *name;
-       struct vm_thread *self;
-
-       self = vm_thread_self();
-       if (!self)
-               return;
-
-       thread = vm_thread_get_java_thread(self);
-
-       name = field_get_object(thread, vm_java_lang_Thread_name);
-
-       char * name_s;
-
-       name_s = vm_string_to_cstr(name);
-       printf("[thread: %s] ", name_s);
-       free(name_s);
-}
-
-void trace_begin(void)
-{
-       pthread_mutex_lock(&trace_mutex);
-       print_current_thread();
-}
-
-void trace_end(void) {
-       pthread_mutex_unlock(&trace_mutex);
-}
+bool opt_trace_compile;
+bool opt_trace_threads;
 
 void trace_method(struct compilation_unit *cu)
 {
@@ -87,11 +57,11 @@ void trace_method(struct compilation_unit *cu)
        unsigned char *p;
        unsigned int i, j;
 
-       printf("\nTRACE: %s.%s%s\n",
+       trace_printf("\nTRACE: %s.%s%s\n",
                method->class->name, method->name, method->type);
 
-       printf("Length: %d\n", method->code_attribute.code_length);
-       printf("Code:\n");
+       trace_printf("Length: %d\n", method->code_attribute.code_length);
+       trace_printf("Code:\n");
        p = method->code_attribute.code;
 
        unsigned int n = method->code_attribute.code_length;
@@ -105,62 +75,62 @@ void trace_method(struct compilation_unit *cu)
                                break;
                }
 
-               printf("[ %04u ] ", i * 16);
+               trace_printf("[ %04u ] ", i * 16);
 
                for (j = 0; j < cols; ++j) {
-                       printf("%02x%s",
+                       trace_printf("%02x%s",
                                p[i * 16 + j],
                                j == 7 ? "  " : " ");
                }
 
-               printf("\n");
+               trace_printf("\n");
        }
 
-       printf("\n\n");
+       trace_printf("\n\n");
 }
 
 void trace_cfg(struct compilation_unit *cu)
 {
        struct basic_block *bb;
 
-       printf("Control Flow Graph:\n\n");
-       printf("  #:\t\tRange\t\tSuccessors\t\tPredecessors\n");
+       trace_printf("Control Flow Graph:\n\n");
+       trace_printf("  #:\t\tRange\t\tSuccessors\t\tPredecessors\n");
 
        for_each_basic_block(bb, &cu->bb_list) {
                unsigned long i;
 
-               printf("  %p\t%lu..%lu\t", bb, bb->start, bb->end);
+               trace_printf("  %p\t%lu..%lu\t", bb, bb->start, bb->end);
                if (bb->is_eh)
-                       printf(" (eh)");
+                       trace_printf(" (eh)");
 
-               printf("\t");
+               trace_printf("\t");
 
                for (i = 0; i < bb->nr_successors; i++) {
                        if (i != 0)
-                               printf(", ");
+                               trace_printf(", ");
 
-                       printf("%p", bb->successors[i]);
+                       trace_printf("%p", bb->successors[i]);
                }
 
                if (i == 0)
-                       printf("none    ");
+                       trace_printf("none    ");
 
-               printf("\t");
+               trace_printf("\t");
 
                for (i = 0; i < bb->nr_predecessors; i++) {
                        if (i != 0)
-                               printf(", ");
+                               trace_printf(", ");
 
-                       printf("%p", bb->predecessors[i]);
+                       trace_printf("%p", bb->predecessors[i]);
                }
 
                if (i == 0)
-                       printf("none    ");
+                       trace_printf("none    ");
 
-               printf("\n");
+               trace_printf("\n");
        }
 
-       printf("\n");
+       trace_printf("\n");
 }
 
 void trace_tree_ir(struct compilation_unit *cu)
@@ -169,17 +139,17 @@ void trace_tree_ir(struct compilation_unit *cu)
        struct statement *stmt;
        struct string *str;
 
-       printf("High-Level Intermediate Representation (HIR):\n\n");
+       trace_printf("High-Level Intermediate Representation (HIR):\n\n");
 
        for_each_basic_block(bb, &cu->bb_list) {
-               printf("[bb %p]:\n\n", bb);
+               trace_printf("[bb %p]:\n\n", bb);
                for_each_stmt(stmt, &bb->stmt_list) {
                        str = alloc_str();
                        tree_print(&stmt->node, str);
-                       printf("%s", str->value);
+                       trace_printf("%s", str->value);
                        free_str(str);
                }
-               printf("\n");
+               trace_printf("\n");
        }
 }
 
@@ -190,11 +160,11 @@ void trace_lir(struct compilation_unit *cu)
        struct string *str;
        struct insn *insn;
 
-       printf("Low-Level Intermediate Representation (LIR):\n\n");
+       trace_printf("Low-Level Intermediate Representation (LIR):\n\n");
 
-       printf("Bytecode   LIR\n");
-       printf("offset     offset    Instruction          Operands\n");
-       printf("---------  -------   -----------          --------\n");
+       trace_printf("Bytecode   LIR\n");
+       trace_printf("offset     offset    Instruction          Operands\n");
+       trace_printf("---------  -------   -----------          --------\n");
 
        for_each_basic_block(bb, &cu->bb_list) {
                for_each_insn(insn, &bb->insn_list) {
@@ -209,16 +179,16 @@ void trace_lir(struct compilation_unit *cu)
 
                                print_bytecode_offset(bc_offset, bc_str);
 
-                               printf("[ %5s ]  ", bc_str->value);
+                               trace_printf("[ %5s ]  ", bc_str->value);
                                free_str(bc_str);
                        }
 
-                       printf(" %5lu:   %s\n", offset++, str->value);
+                       trace_printf(" %5lu:   %s\n", offset++, str->value);
                        free_str(str);
                }
        }
 
-       printf("\n");
+       trace_printf("\n");
 }
 
 static void
@@ -229,7 +199,7 @@ print_var_liveness(struct compilation_unit *cu, struct 
var_info *var)
        unsigned long offset;
        struct insn *insn;
 
-       printf("  %2lu: ", var->vreg);
+       trace_printf("  %2lu: ", var->vreg);
 
        offset = 0;
        for_each_basic_block(bb, &cu->bb_list) {
@@ -237,24 +207,24 @@ print_var_liveness(struct compilation_unit *cu, struct 
var_info *var)
                        if (in_range(range, offset)) {
                                if (next_use_pos(var->interval, offset) == 
offset) {
                                        /* In use */
-                                       printf("UUU");
+                                       trace_printf("UUU");
                                } else {
                                        if (var->interval->reg == 
REG_UNASSIGNED)
-                                               printf("***");
+                                               trace_printf("***");
                                        else
-                                               printf("---");
+                                               trace_printf("---");
                                }
                        }
                        else
-                               printf("   ");
+                               trace_printf("   ");
 
                        offset++;
                }
        }
        if (!range_is_empty(range))
-               printf(" (start: %2lu, end: %2lu)\n", range->start, range->end);
+               trace_printf(" (start: %2lu, end: %2lu)\n", range->start, 
range->end);
        else
-               printf(" (empty)\n");
+               trace_printf(" (empty)\n");
 }
 
 void trace_liveness(struct compilation_unit *cu)
@@ -264,83 +234,85 @@ void trace_liveness(struct compilation_unit *cu)
        unsigned long offset;
        struct insn *insn;
 
-       printf("Liveness:\n\n");
+       trace_printf("Liveness:\n\n");
 
-       printf("Legend: (U) In use, (-) Fixed register, (*) Non-fixed 
register\n\n");
+       trace_printf("Legend: (U) In use, (-) Fixed register, (*) Non-fixed 
register\n\n");
 
-       printf("      ");
+       trace_printf("      ");
        offset = 0;
        for_each_basic_block(bb, &cu->bb_list) {
                for_each_insn(insn, &bb->insn_list) {
-                       printf("%-2lu ", offset++);
+                       trace_printf("%-2lu ", offset++);
                }
        }
-       printf("\n");
+       trace_printf("\n");
 
        for_each_variable(var, cu->var_infos)
                print_var_liveness(cu, var);
 
-       printf("\n");
+       trace_printf("\n");
 }
 
 void trace_regalloc(struct compilation_unit *cu)
 {
        struct var_info *var;
 
-       printf("Register Allocation:\n\n");
+       trace_printf("Register Allocation:\n\n");
 
        for_each_variable(var, cu->var_infos) {
                struct live_interval *interval;
 
                for (interval = var->interval; interval != NULL; interval = 
interval->next_child) {
-                       printf("  %2lu (pos: %2ld-%2lu):", var->vreg, (signed 
long)interval->range.start, interval->range.end);
-                       printf("\t%s", reg_name(interval->reg));
-                       printf("\t%s", interval->fixed_reg ? "fixed\t" : 
"non-fixed");
+                       trace_printf("  %2lu (pos: %2ld-%2lu):", var->vreg, 
(signed long)interval->range.start, interval->range.end);
+                       trace_printf("\t%s", reg_name(interval->reg));
+                       trace_printf("\t%s", interval->fixed_reg ? "fixed\t" : 
"non-fixed");
                        if (interval->need_spill) {
                                unsigned long ndx = -1;
 
                                if (interval->spill_slot)
                                        ndx = interval->spill_slot->index;
 
-                               printf("\tspill (%ld)", ndx);
+                               trace_printf("\tspill (%ld)", ndx);
                        } else
-                               printf("\tno spill  ");
+                               trace_printf("\tno spill  ");
 
                        if (interval->need_reload) {
                                unsigned long ndx = -1;
 
                                if (interval->spill_parent && 
interval->spill_parent->spill_slot)
                                        ndx = 
interval->spill_parent->spill_slot->index;
-                               printf("\treload (%ld)", ndx);
+                               trace_printf("\treload (%ld)", ndx);
                        } else
-                               printf("\tno reload  ");
-                       printf("\n");
+                               trace_printf("\tno reload  ");
+                       trace_printf("\n");
                }
        }
-       printf("\n");
+       trace_printf("\n");
 }
 
 void trace_machine_code(struct compilation_unit *cu)
 {
        void *start, *end;
 
-       printf("Disassembler Listing:\n\n");
+       trace_printf("Disassembler Listing:\n\n");
 
        start  = buffer_ptr(cu->objcode);
        end = buffer_current(cu->objcode);
 
        disassemble(cu, start, end);
-       printf("\n");
+       trace_printf("\n");
 }
 
 void trace_magic_trampoline(struct compilation_unit *cu)
 {
-       printf("jit_magic_trampoline: ret0=%p, ret1=%p: %s.%s #%d\n",
+       trace_printf("jit_magic_trampoline: ret0=%p, ret1=%p: %s.%s #%d\n",
               __builtin_return_address(1),
               __builtin_return_address(2),
               cu->method->class->name,
               cu->method->name,
               cu->method->method_index);
+
+       trace_flush();
 }
 
 static void print_arg(enum vm_type arg_type, const unsigned long *args,
@@ -352,11 +324,11 @@ static void print_arg(enum vm_type arg_type, const 
unsigned long *args,
                value = *(unsigned long long*)(args + *arg_index);
                (*arg_index) += 2;
 
-               printf("0x%llx", value);
+               trace_printf("0x%llx", value);
                return;
        }
 
-       printf("0x%lx ", args[*arg_index]);
+       trace_printf("0x%lx ", args[*arg_index]);
 
        if (arg_type == J_REFERENCE) {
                struct vm_object *obj;
@@ -364,12 +336,12 @@ static void print_arg(enum vm_type arg_type, const 
unsigned long *args,
                obj = (struct vm_object *)args[*arg_index];
 
                if (!obj) {
-                       printf("null");
+                       trace_printf("null");
                        goto out;
                }
 
                if (!is_on_heap((unsigned long)obj)) {
-                       printf("*** pointer not on heap ***");
+                       trace_printf("*** pointer not on heap ***");
                        goto out;
                }
 
@@ -377,16 +349,16 @@ static void print_arg(enum vm_type arg_type, const 
unsigned long *args,
                        char *str;
 
                        str = vm_string_to_cstr(obj);
-                       printf("= \"%s\"", str);
+                       trace_printf("= \"%s\"", str);
                        free(str);
                }
 
-               printf(" (%s)", obj->class->name);
+               trace_printf(" (%s)", obj->class->name);
        }
 
  out:
        (*arg_index)++;
-       printf("\n");
+       trace_printf("\n");
 }
 
 static void trace_invoke_args(struct vm_method *vmm,
@@ -402,21 +374,21 @@ static void trace_invoke_args(struct vm_method *vmm,
        arg_index = 0;
 
        if (!vm_method_is_static(vmm)) {
-               printf("\tthis\t: ");
+               trace_printf("\tthis\t: ");
                print_arg(J_REFERENCE, frame->args, &arg_index);
        }
 
        type_str = vmm->type;
 
        if (!strncmp(type_str, "()", 2)) {
-               printf("\targs\t: none\n");
+               trace_printf("\targs\t: none\n");
                return;
        }
 
-       printf("\targs\t:\n");
+       trace_printf("\targs\t:\n");
 
        while ((type_str = parse_method_args(type_str, &arg_type))) {
-               printf("\t   %-12s: ", get_vm_type_name(arg_type));
+               trace_printf("\t   %-12s: ", get_vm_type_name(arg_type));
                print_arg(arg_type, frame->args, &arg_index);
        }
 }
@@ -429,23 +401,23 @@ static void print_source_and_line(struct compilation_unit 
*cu,
 
        source_file = cu->method->class->source_file_name;
        if (source_file)
-               printf("%s", source_file);
+               trace_printf("%s", source_file);
        else
-               printf("UNKNOWN");
+               trace_printf("UNKNOWN");
 
        pc = native_ptr_to_bytecode_offset(cu, ptr);
        if (pc == BC_OFFSET_UNKNOWN)
                return;
 
-       printf(":%d", bytecode_offset_to_line_no(cu->method, pc));
+       trace_printf(":%d", bytecode_offset_to_line_no(cu->method, pc));
 }
 
 static void trace_return_address(struct jit_stack_frame *frame)
 {
-       printf("\tret\t: %p:", (void*)frame->return_address);
+       trace_printf("\tret\t: %p:", (void*)frame->return_address);
 
        if (is_native(frame->return_address)) {
-               printf(" (native)\n");
+               trace_printf(" (native)\n");
        } else {
                struct compilation_unit *cu;
                struct vm_method *vmm;
@@ -453,17 +425,17 @@ static void trace_return_address(struct jit_stack_frame 
*frame)
 
                cu = jit_lookup_cu(frame->return_address);
                if (!cu) {
-                       printf(" (no compilation unit mapping)\n");
+                       trace_printf(" (no compilation unit mapping)\n");
                        return;
                }
 
                vmm = cu->method;;
                vmc = vmm->class;
 
-               printf(" %s.%s%s\n", vmc->name, vmm->name, vmm->type );
-               printf("\t\t  (");
+               trace_printf(" %s.%s%s\n", vmc->name, vmm->name, vmm->type );
+               trace_printf("\t\t  (");
                print_source_and_line(cu, (void *) frame->return_address);
-               printf(")\n");
+               trace_printf(")\n");
        }
 }
 
@@ -472,21 +444,20 @@ void trace_invoke(struct compilation_unit *cu)
        struct vm_method *vmm = cu->method;
        struct vm_class *vmc = vmm->class;
 
-       trace_begin();
-
-       printf("trace invoke: %s.%s%s\n", vmc->name, vmm->name, vmm->type);
+       trace_printf("trace invoke: %s.%s%s\n", vmc->name, vmm->name,
+                    vmm->type);
 
        if (opt_trace_invoke_verbose) {
                struct jit_stack_frame *frame;
 
                frame =  __builtin_frame_address(1);
 
-               printf("\tentry\t: %p\n", buffer_ptr(cu->objcode));
+               trace_printf("\tentry\t: %p\n", buffer_ptr(cu->objcode));
                trace_return_address(frame);
                trace_invoke_args(vmm, frame);
        }
 
-       trace_end();
+       trace_flush();
 }
 
 void trace_exception(struct compilation_unit *cu, struct jit_stack_frame 
*frame,
@@ -503,23 +474,27 @@ void trace_exception(struct compilation_unit *cu, struct 
jit_stack_frame *frame,
        exception = exception_occurred();
        assert(exception);
 
-       printf("trace exception: exception object %p (%s) thrown\n",
+       trace_printf("trace exception: exception object %p (%s) thrown\n",
               exception, exception->class->name);
 
-       printf("\tfrom\t: %p: %s.%s%s\n", native_ptr, vmc->name, vmm->name,
+       trace_printf("\tfrom\t: %p: %s.%s%s\n", native_ptr, vmc->name, 
vmm->name,
               vmm->type);
-       printf("\t\t  (");
+       trace_printf("\t\t  (");
        print_source_and_line(cu, native_ptr);
-       printf(")\n");
+       trace_printf(")\n");
+
+       /* XXX: trace is flushed in one of the action tracers. */
 }
 
 void trace_exception_handler(struct compilation_unit *cu,
                             unsigned char *ptr)
 {
-       printf("\taction\t: jump to handler at %p\n", ptr);
-       printf("\t\t  (");
+       trace_printf("\taction\t: jump to handler at %p\n", ptr);
+       trace_printf("\t\t  (");
        print_source_and_line(cu, ptr);
-       printf(")\n");
+       trace_printf(")\n");
+
+       trace_flush();
 }
 
 void trace_exception_unwind(struct jit_stack_frame *frame)
@@ -533,27 +508,31 @@ void trace_exception_unwind(struct jit_stack_frame *frame)
        vmm = cu->method;
        vmc = vmm->class;
 
-       printf("\taction\t: unwind to %p: %s.%s%s\n",
+       trace_printf("\taction\t: unwind to %p: %s.%s%s\n",
               (void*)frame->return_address, vmc->name, vmm->name, vmm->type);
-       printf("\t\t  (");
+       trace_printf("\t\t  (");
        print_source_and_line(cu, (void *) frame->return_address);
-       printf(")\n");
+       trace_printf(")\n");
+
+       trace_flush();
 }
 
 void trace_exception_unwind_to_native(struct jit_stack_frame *frame)
 {
-       printf("\taction\t: unwind to native caller at %p\n",
+       trace_printf("\taction\t: unwind to native caller at %p\n",
               (void*)frame->return_address);
+
+       trace_flush();
 }
 
 void trace_bytecode(struct vm_method *method)
 {
-       printf("Code:\n");
+       trace_printf("Code:\n");
        bytecode_disassemble(method->code_attribute.code,
                             method->code_attribute.code_length);
-       printf("\nException table:\n");
+       trace_printf("\nException table:\n");
        print_exception_table(method,
                method->code_attribute.exception_table,
                method->code_attribute.exception_table_length);
-       printf("\n");
+       trace_printf("\n");
 }
diff --git a/test/arch-x86/Makefile b/test/arch-x86/Makefile
index 078685d..de408a5 100644
--- a/test/arch-x86/Makefile
+++ b/test/arch-x86/Makefile
@@ -67,6 +67,7 @@ TOPLEVEL_OBJS := \
        vm/stack-trace.o \
        vm/static.o \
        vm/thread.o \
+       vm/trace.o \
        vm/types.o \
        vm/utf8.o \
        vm/zalloc.o \
diff --git a/test/jit/Makefile b/test/jit/Makefile
index 75055d7..dcf8e20 100644
--- a/test/jit/Makefile
+++ b/test/jit/Makefile
@@ -54,6 +54,7 @@ TOPLEVEL_OBJS := \
        vm/die.o \
        vm/guard-page.o \
        vm/stack.o \
+       vm/trace.o \
        vm/types.o \
        vm/zalloc.o \
        arch/mmix/instruction.o \
@@ -67,6 +68,7 @@ TOPLEVEL_OBJS := \
        test/vm/preload-stub.o \
        test/vm/jni-stub.o \
        test/vm/stack-trace-stub.o \
+       test/vm/thread-stub.o \
        test/jit/trace-stub.o
 
 TEST_OBJS := \
diff --git a/test/jit/trace-stub.c b/test/jit/trace-stub.c
index 5b0d8bf..3883339 100644
--- a/test/jit/trace-stub.c
+++ b/test/jit/trace-stub.c
@@ -8,6 +8,7 @@ struct compilation_unit;
 bool opt_trace_invoke = false;
 bool opt_trace_exceptions = false;
 bool opt_trace_bytecode = false;
+bool opt_trace_threads = false;
 
 void trace_invoke(struct compilation_unit *cu)
 {
diff --git a/test/vm/Makefile b/test/vm/Makefile
index b29df2a..c6a6c39 100644
--- a/test/vm/Makefile
+++ b/test/vm/Makefile
@@ -13,10 +13,13 @@ TOPLEVEL_OBJS :=                    \
        vm/die.o                        \
        vm/natives.o                    \
        vm/stack.o                      \
+       vm/trace.o                      \
        vm/types.o                      \
        vm/zalloc.o                     \
        test/libharness/libharness.o    \
-       test/vm/stack-trace-stub.o
+       test/jit/trace-stub.o           \
+       test/vm/stack-trace-stub.o      \
+       test/vm/thread-stub.o
 
 TEST_OBJS :=                           \
        bitset-test.o                   \
diff --git a/test/vm/thread-stub.c b/test/vm/thread-stub.c
new file mode 100644
index 0000000..a511fcb
--- /dev/null
+++ b/test/vm/thread-stub.c
@@ -0,0 +1,8 @@
+#include "vm/thread.h"
+
+__thread struct vm_exec_env current_exec_env;
+
+char *vm_thread_get_name(struct vm_thread *thread)
+{
+       return NULL;
+}
diff --git a/vm/bytecodes.c b/vm/bytecodes.c
index 4d78d38..163a423 100644
--- a/vm/bytecodes.c
+++ b/vm/bytecodes.c
@@ -12,6 +12,9 @@
 #include "vm/bytecodes.h"
 #include "vm/die.h"
 #include "vm/opcodes.h"
+#include "vm/trace.h"
+
+#include "jit/compiler.h"
 
 #include <assert.h>
 #include <stdint.h>
@@ -211,11 +214,11 @@ void bytecode_disassemble(const unsigned char *code, 
unsigned long size)
 
                size = bc_insn_size(&code[pc]);
 
-               printf("   [ %-3ld ]  0x%02x  ", pc, code[pc]);
+               trace_printf("   [ %-3ld ]  0x%02x  ", pc, code[pc]);
 
                opc_name = bc_get_insn_name(&code[pc]);
                if (!opc_name) {
-                       printf("(string alloc failed)\n");
+                       trace_printf("(string alloc failed)\n");
                        continue;
                }
 
@@ -227,20 +230,20 @@ void bytecode_disassemble(const unsigned char *code, 
unsigned long size)
                }
 
                if (size > 1)
-                       printf("%-14s", opc_name);
+                       trace_printf("%-14s", opc_name);
                else
-                       printf("%s", opc_name);
+                       trace_printf("%s", opc_name);
 
                free(opc_name);
 
                if (bc_is_branch(code[_pc])) {
-                       printf(" %ld\n", bc_target_off(&code[_pc]) + _pc);
+                       trace_printf(" %ld\n", bc_target_off(&code[_pc]) + _pc);
                        continue;
                }
 
                for (int i = 1; i < size; i++)
-                       printf(" 0x%02x", (unsigned int)code[_pc + i]);
+                       trace_printf(" 0x%02x", (unsigned int)code[_pc + i]);
 
-               printf("\n");
+               trace_printf("\n");
        }
 }
diff --git a/vm/classloader.c b/vm/classloader.c
index 3f436af..b612c86 100644
--- a/vm/classloader.c
+++ b/vm/classloader.c
@@ -13,6 +13,7 @@
 #include "vm/class.h"
 #include "vm/die.h"
 #include "vm/backtrace.h"
+#include "vm/trace.h"
 
 bool opt_trace_classloader;
 static __thread int trace_classloader_level = 0;
@@ -25,10 +26,9 @@ static inline void trace_push(const char *class_name)
        assert(trace_classloader_level >= 0);
 
        if (opt_trace_classloader) {
-               trace_begin();
-               fprintf(stderr, "classloader: %*s%s\n",
-                       trace_classloader_level, "", class_name);
-               trace_end();
+               trace_printf("classloader: %*s%s\n",
+                            trace_classloader_level, "", class_name);
+               trace_flush();
        }
 
        ++trace_classloader_level;
diff --git a/vm/jato.c b/vm/jato.c
index 1319ba6..96f80ae 100644
--- a/vm/jato.c
+++ b/vm/jato.c
@@ -685,6 +685,7 @@ static void handle_trace_asm(void)
 {
        opt_trace_method = true;
        opt_trace_machine_code = true;
+       opt_trace_compile = true;
 }
 
 static void handle_trace_bytecode_offset(void)
@@ -729,12 +730,19 @@ static void handle_trace_jit(void)
        opt_trace_machine_code = true;
        opt_trace_magic_trampoline = true;
        opt_trace_bytecode_offset = true;
+       opt_trace_compile = true;
 }
 
 static void handle_trace_bytecode(void)
 {
        opt_trace_bytecode = true;
        opt_trace_method = true;
+       opt_trace_compile = true;
+}
+
+static void handle_trace_threads(void)
+{
+       opt_trace_threads = true;
 }
 
 static void handle_trace_trampoline(void)
@@ -812,6 +820,7 @@ const struct option options[] = {
        DEFINE_OPTION("Xtrace:invoke-verbose",  handle_trace_invoke_verbose),
        DEFINE_OPTION("Xtrace:itable",          handle_trace_itable),
        DEFINE_OPTION("Xtrace:jit",             handle_trace_jit),
+       DEFINE_OPTION("Xtrace:threads",         handle_trace_threads),
        DEFINE_OPTION("Xtrace:trampoline",      handle_trace_trampoline),
 };
 
diff --git a/vm/stack-trace.c b/vm/stack-trace.c
index 95a8bf6..935a524 100644
--- a/vm/stack-trace.c
+++ b/vm/stack-trace.c
@@ -38,6 +38,7 @@
 #include "vm/stack-trace.h"
 #include "vm/system.h"
 #include "vm/thread.h"
+#include "vm/trace.h"
 
 #include "jit/bc-offset-mapping.h"
 #include "jit/cu-mapping.h"
@@ -431,19 +432,19 @@ void print_java_stack_trace_elem(struct stack_trace_elem 
*elem)
        cu = stack_trace_elem_get_cu(elem);
 
        struct vm_method *vmm = cu->method;
-       printf("%s.%s", vmm->class->name, vmm->name);
+       trace_printf("%s.%s", vmm->class->name, vmm->name);
 
        if (vm_method_is_native(vmm)) {
-               printf("(Native Method)");
+               trace_printf("(Native Method)");
                return;
        }
 
        if (!vmm->class->source_file_name) {
-               printf("(Unknown Source)");
+               trace_printf("(Unknown Source)");
                return;
        }
 
-       printf("(%s", vmm->class->source_file_name);
+       trace_printf("(%s", vmm->class->source_file_name);
 
        if (elem->type == STACK_TRACE_ELEM_TYPE_TRAMPOLINE)
                bc_offset = 0;
@@ -458,10 +459,10 @@ void print_java_stack_trace_elem(struct stack_trace_elem 
*elem)
        if (line_no == -1)
                goto out;
 
-       printf(":%d", line_no);
+       trace_printf(":%d", line_no);
 
  out:
-       printf(")");
+       trace_printf(")");
 }
 
 /**
@@ -719,18 +720,18 @@ const char *stack_trace_elem_type_name(enum 
stack_trace_elem_type type)
 
 static void show_mixed_stack_trace(struct stack_trace_elem *elem)
 {
-       printf("Native and JAVA stack trace:\n");
+       trace_printf("Native and JAVA stack trace:\n");
        do {
-               printf(" [<%08lx>] %-10s : ", elem->addr,
+               trace_printf(" [<%08lx>] %-10s : ", elem->addr,
                       stack_trace_elem_type_name(elem->type));
 
                if (elem->type != STACK_TRACE_ELEM_TYPE_OTHER) {
                        print_java_stack_trace_elem(elem);
-                       printf("\n");
+                       trace_printf("\n");
 
-                       printf("%-27s"," ");
+                       trace_printf("%-27s"," ");
                        if (!show_exe_function((void *) elem->addr))
-                               printf("\r");
+                               trace_printf("\r");
 
                        continue;
                }
@@ -749,6 +750,8 @@ void print_trace(void)
        stack_trace_elem_next(&elem);
 
        show_mixed_stack_trace(&elem);
+
+       trace_flush();
 }
 
 void print_trace_from(unsigned long eip, void *frame)
diff --git a/vm/trace.c b/vm/trace.c
new file mode 100644
index 0000000..6e8fc02
--- /dev/null
+++ b/vm/trace.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2009 Tomasz Grabiec
+ *
+ * This file is released under the GPL version 2 with the following
+ * clarification and special exception:
+ *
+ *     Linking this library statically or dynamically with other modules is
+ *     making a combined work based on this library. Thus, the terms and
+ *     conditions of the GNU General Public License cover the whole
+ *     combination.
+ *
+ *     As a special exception, the copyright holders of this library give you
+ *     permission to link this library with independent modules to produce an
+ *     executable, regardless of the license terms of these independent
+ *     modules, and to copy and distribute the resulting executable under terms
+ *     of your choice, provided that you also meet, for each linked independent
+ *     module, the terms and conditions of the license of that module. An
+ *     independent module is a module which is not derived from or based on
+ *     this library. If you modify this library, you may extend this exception
+ *     to your version of the library, but you are not obligated to do so. If
+ *     you do not wish to do so, delete this exception statement from your
+ *     version.
+ *
+ * Please refer to the file LICENSE for details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "jit/compiler.h"
+
+#include "lib/string.h"
+
+#include "vm/die.h"
+#include "vm/thread.h"
+#include "vm/trace.h"
+
+static pthread_mutex_t trace_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Holds the trace output. It it initialized in trace_begin() and
+   printed in trace_end(). */
+static __thread struct string *trace_buffer = NULL;
+
+static void ensure_trace_buffer(void)
+{
+       if (trace_buffer)
+               return;
+
+       trace_buffer = alloc_str();
+       if (!trace_buffer)
+               error("out of memory");
+}
+
+int trace_printf(const char *fmt, ...)
+{
+       int err;
+       va_list args;
+
+       ensure_trace_buffer();
+
+       va_start(args, fmt);
+       err = str_vappend(trace_buffer, fmt, args);
+       va_end(args);
+       return err;
+}
+
+void trace_flush(void) {
+       struct vm_thread *self;
+       char *thread_name;
+       char *strtok_ptr;
+       char *line;
+
+       ensure_trace_buffer();
+
+       self = vm_thread_self();
+       if (self)
+               thread_name = vm_thread_get_name(self);
+       else
+               thread_name = "unknown";
+
+       pthread_mutex_lock(&trace_mutex);
+
+       if (opt_trace_threads) {
+               line = strtok_r(trace_buffer->value, "\n", &strtok_ptr);
+               while (line) {
+                       fprintf(stderr, "[%s] %s\n", thread_name, line);
+
+                       line = strtok_r(NULL, "\n", &strtok_ptr);
+               }
+       } else {
+               fprintf(stderr, "%s", trace_buffer->value);
+       }
+
+       pthread_mutex_unlock(&trace_mutex);
+
+       if (self)
+               free(thread_name);
+
+       trace_buffer->length = 0;
+}
-- 
1.6.0.6


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with 
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Jatovm-devel mailing list
Jatovm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jatovm-devel

Reply via email to