Merge pull request #3395 from lambdageek/dev/handles-strings
[mono.git] / mono / profiler / decode.c
index e57211635ee700b0ea1bea48015d8709333b89fd..355e4c95388770496902b501920f4d9b0fd8e959 100644 (file)
@@ -6,6 +6,7 @@
  *   Alex Rønne Petersen (alexrp@xamarin.com)
  *
  * Copyright 2010 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
 /*
@@ -353,6 +354,7 @@ section_name (int section)
        case MONO_COUNTER_SECURITY: return "Mono Security";
        case MONO_COUNTER_RUNTIME: return "Mono Runtime";
        case MONO_COUNTER_SYSTEM: return "Mono System";
+       case MONO_COUNTER_PROFILER: return "Mono Profiler";
        default: return "<unknown>";
        }
 }
@@ -1860,9 +1862,23 @@ gc_event_name (int ev)
        case MONO_GC_EVENT_RECLAIM_END: return "reclaim end";
        case MONO_GC_EVENT_END: return "end";
        case MONO_GC_EVENT_PRE_STOP_WORLD: return "pre stop";
+       case MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED: return "pre stop lock";
        case MONO_GC_EVENT_POST_STOP_WORLD: return "post stop";
        case MONO_GC_EVENT_PRE_START_WORLD: return "pre start";
        case MONO_GC_EVENT_POST_START_WORLD: return "post start";
+       case MONO_GC_EVENT_POST_START_WORLD_UNLOCKED: return "post start unlock";
+       default:
+               return "unknown";
+       }
+}
+
+static const char*
+sync_point_name (int type)
+{
+       switch (type) {
+       case SYNC_POINT_PERIODIC: return "periodic";
+       case SYNC_POINT_WORLD_STOP: return "world stop";
+       case SYNC_POINT_WORLD_START: return "world start";
        default:
                return "unknown";
        }
@@ -1954,21 +1970,25 @@ get_root_name (int rtype)
 }
 
 static MethodDesc**
-decode_bt (MethodDesc** sframes, int *size, unsigned char *p, unsigned char **endp, intptr_t ptr_base)
+decode_bt (ProfContext *ctx, MethodDesc** sframes, int *size, unsigned char *p, unsigned char **endp, intptr_t ptr_base, intptr_t *method_base)
 {
        MethodDesc **frames;
        int i;
-       int flags = decode_uleb128 (p, &p);
+       if (ctx->data_version < 13)
+               decode_uleb128 (p, &p); /* flags */
        int count = decode_uleb128 (p, &p);
-       if (flags != 0)
-               return NULL;
        if (count > *size)
                frames = (MethodDesc **)malloc (count * sizeof (void*));
        else
                frames = sframes;
        for (i = 0; i < count; ++i) {
                intptr_t ptrdiff = decode_sleb128 (p, &p);
-               frames [i] = lookup_method (ptr_base + ptrdiff);
+               if (ctx->data_version > 12) {
+                       *method_base += ptrdiff;
+                       frames [i] = lookup_method (*method_base);
+               } else {
+                       frames [i] = lookup_method (ptr_base + ptrdiff);
+               }
        }
        *size = count;
        *endp = p;
@@ -2255,8 +2275,6 @@ decode_buffer (ProfContext *ctx)
                        time_from += startup_time;
                        time_to += startup_time;
                }
-               if (!thread->name)
-                       thread->name = pstrdup ("Main");
        }
        for (i = 0; i < thread->stack_id; ++i)
                thread->stack [i]->recurse_count++;
@@ -2279,8 +2297,16 @@ decode_buffer (ProfContext *ctx)
                                if (new_size > max_heap_size)
                                        max_heap_size = new_size;
                        } else if (subtype == TYPE_GC_EVENT) {
-                               uint64_t ev = decode_uleb128 (p, &p);
-                               int gen = decode_uleb128 (p, &p);
+                               uint64_t ev;
+                               if (ctx->data_version > 12)
+                                       ev = *p++;
+                               else
+                                       ev = decode_uleb128 (p, &p);
+                               int gen;
+                               if (ctx->data_version > 12)
+                                       gen = *p++;
+                               else
+                                       gen = decode_uleb128 (p, &p);
                                if (debug)
                                        fprintf (outfile, "gc event for gen%d: %s at %llu (thread: 0x%zx)\n", gen, gc_event_name (ev), (unsigned long long) time_base, thread->thread_id);
                                if (gen > 2) {
@@ -2318,7 +2344,7 @@ decode_buffer (ProfContext *ctx)
                                intptr_t objdiff = decode_sleb128 (p, &p);
                                if (has_bt) {
                                        num_bt = 8;
-                                       frames = decode_bt (sframes, &num_bt, p, &p, ptr_base);
+                                       frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
                                        if (!frames) {
                                                fprintf (outfile, "Cannot load backtrace\n");
                                                return 0;
@@ -2352,7 +2378,7 @@ decode_buffer (ProfContext *ctx)
                                uint32_t handle = decode_uleb128 (p, &p);
                                if (has_bt) {
                                        num_bt = 8;
-                                       frames = decode_bt (sframes, &num_bt, p, &p, ptr_base);
+                                       frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
                                        if (!frames) {
                                                fprintf (outfile, "Cannot load backtrace\n");
                                                return 0;
@@ -2374,6 +2400,21 @@ decode_buffer (ProfContext *ctx)
                                        fprintf (outfile, "handle (%s) %u destroyed\n", get_handle_name (htype), handle);
                                if (frames != sframes)
                                        free (frames);
+                       } else if (subtype == TYPE_GC_FINALIZE_START) {
+                               // TODO: Generate a finalizer report based on these events.
+                               if (debug)
+                                       fprintf (outfile, "gc finalizer queue being processed at %llu\n", (unsigned long long) time_base);
+                       } else if (subtype == TYPE_GC_FINALIZE_END) {
+                               if (debug)
+                                       fprintf (outfile, "gc finalizer queue finished processing at %llu\n", (unsigned long long) time_base);
+                       } else if (subtype == TYPE_GC_FINALIZE_OBJECT_START) {
+                               intptr_t objdiff = decode_sleb128 (p, &p);
+                               if (debug)
+                                       fprintf (outfile, "gc finalizing object %p at %llu\n", (void *) OBJ_ADDR (objdiff), (unsigned long long) time_base);
+                       } else if (subtype == TYPE_GC_FINALIZE_OBJECT_END) {
+                               intptr_t objdiff = decode_sleb128 (p, &p);
+                               if (debug)
+                                       fprintf (outfile, "gc finalized object %p at %llu\n", (void *) OBJ_ADDR (objdiff), (unsigned long long) time_base);
                        }
                        break;
                }
@@ -2387,11 +2428,8 @@ decode_buffer (ProfContext *ctx)
                        time_base += tdiff;
                        if (mtype == TYPE_CLASS) {
                                intptr_t imptrdiff = decode_sleb128 (p, &p);
-                               uint64_t flags = decode_uleb128 (p, &p);
-                               if (flags) {
-                                       fprintf (outfile, "non-zero flags in class\n");
-                                       return 0;
-                               }
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
                                if (debug)
                                        fprintf (outfile, "%s class %p (%s in %p) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), p, (void*)(ptr_base + imptrdiff), (unsigned long long) time_base);
                                if (subtype == TYPE_END_LOAD)
@@ -2399,11 +2437,8 @@ decode_buffer (ProfContext *ctx)
                                while (*p) p++;
                                p++;
                        } else if (mtype == TYPE_IMAGE) {
-                               uint64_t flags = decode_uleb128 (p, &p);
-                               if (flags) {
-                                       fprintf (outfile, "non-zero flags in image\n");
-                                       return 0;
-                               }
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
                                if (debug)
                                        fprintf (outfile, "%s image %p (%s) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), p, (unsigned long long) time_base);
                                if (subtype == TYPE_END_LOAD)
@@ -2411,11 +2446,8 @@ decode_buffer (ProfContext *ctx)
                                while (*p) p++;
                                p++;
                        } else if (mtype == TYPE_ASSEMBLY) {
-                               uint64_t flags = decode_uleb128 (p, &p);
-                               if (flags) {
-                                       fprintf (outfile, "non-zero flags in assembly\n");
-                                       return 0;
-                               }
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
                                if (debug)
                                        fprintf (outfile, "%s assembly %p (%s) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), p, (unsigned long long) time_base);
                                if (subtype == TYPE_END_LOAD)
@@ -2423,11 +2455,8 @@ decode_buffer (ProfContext *ctx)
                                while (*p) p++;
                                p++;
                        } else if (mtype == TYPE_DOMAIN) {
-                               uint64_t flags = decode_uleb128 (p, &p);
-                               if (flags) {
-                                       fprintf (outfile, "non-zero flags in domain\n");
-                                       return 0;
-                               }
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
                                DomainContext *nd = get_domain (ctx, ptr_base + ptrdiff);
                                /* no subtype means it's a name event, rather than start/stop */
                                if (subtype == 0)
@@ -2443,22 +2472,16 @@ decode_buffer (ProfContext *ctx)
                                        p++;
                                }
                        } else if (mtype == TYPE_CONTEXT) {
-                               uint64_t flags = decode_uleb128 (p, &p);
-                               if (flags) {
-                                       fprintf (outfile, "non-zero flags in context\n");
-                                       return 0;
-                               }
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
                                intptr_t domaindiff = decode_sleb128 (p, &p);
                                if (debug)
                                        fprintf (outfile, "%s context %p (%p) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), (void *) (ptr_base + domaindiff), (unsigned long long) time_base);
                                if (subtype == TYPE_END_LOAD)
                                        get_remctx (ctx, ptr_base + ptrdiff)->domain_id = ptr_base + domaindiff;
                        } else if (mtype == TYPE_THREAD) {
-                               uint64_t flags = decode_uleb128 (p, &p);
-                               if (flags) {
-                                       fprintf (outfile, "non-zero flags in thread\n");
-                                       return 0;
-                               }
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
                                ThreadContext *nt = get_thread (ctx, ptr_base + ptrdiff);
                                /* no subtype means it's a name event, rather than start/stop */
                                if (subtype == 0)
@@ -2493,7 +2516,7 @@ decode_buffer (ProfContext *ctx)
                                fprintf (outfile, "alloced object %p, size %llu (%s) at %llu\n", (void*)OBJ_ADDR (objdiff), (unsigned long long) len, lookup_class (ptr_base + ptrdiff)->name, (unsigned long long) time_base);
                        if (has_bt) {
                                num_bt = 8;
-                               frames = decode_bt (sframes, &num_bt, p, &p, ptr_base);
+                               frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
                                if (!frames) {
                                        fprintf (outfile, "Cannot load backtrace\n");
                                        return 0;
@@ -2561,7 +2584,14 @@ decode_buffer (ProfContext *ctx)
                        if (subtype == TYPE_HEAP_OBJECT) {
                                HeapObjectDesc *ho = NULL;
                                int i;
-                               intptr_t objdiff = decode_sleb128 (p + 1, &p);
+                               intptr_t objdiff;
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       objdiff = decode_sleb128 (p, &p);
+                               } else
+                                       objdiff = decode_sleb128 (p + 1, &p);
                                intptr_t ptrdiff = decode_sleb128 (p, &p);
                                uint64_t size = decode_uleb128 (p, &p);
                                uintptr_t num = decode_uleb128 (p, &p);
@@ -2594,12 +2624,23 @@ decode_buffer (ProfContext *ctx)
                                if (debug && size)
                                        fprintf (outfile, "traced object %p, size %llu (%s), refs: %zd\n", (void*)OBJ_ADDR (objdiff), (unsigned long long) size, cd->name, num);
                        } else if (subtype == TYPE_HEAP_ROOT) {
-                               uintptr_t num = decode_uleb128 (p + 1, &p);
+                               uintptr_t num;
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       num = decode_uleb128 (p, &p);
+                               } else
+                                       num = decode_uleb128 (p + 1, &p);
                                uintptr_t gc_num G_GNUC_UNUSED = decode_uleb128 (p, &p);
                                int i;
                                for (i = 0; i < num; ++i) {
                                        intptr_t objdiff = decode_sleb128 (p, &p);
-                                       int root_type = decode_uleb128 (p, &p);
+                                       int root_type;
+                                       if (ctx->data_version > 12)
+                                               root_type = *p++;
+                                       else
+                                               root_type = decode_uleb128 (p, &p);
                                        /* we just discard the extra info for now */
                                        uintptr_t extra_info = decode_uleb128 (p, &p);
                                        if (debug)
@@ -2670,7 +2711,7 @@ decode_buffer (ProfContext *ctx)
                                }
                                if (has_bt) {
                                        num_bt = 8;
-                                       frames = decode_bt (sframes, &num_bt, p, &p, ptr_base);
+                                       frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
                                        if (!frames) {
                                                fprintf (outfile, "Cannot load backtrace\n");
                                                return 0;
@@ -2725,7 +2766,11 @@ decode_buffer (ProfContext *ctx)
                        if (!(time_base >= time_from && time_base < time_to))
                                record = 0;
                        if (subtype == TYPE_CLAUSE) {
-                               int clause_type = decode_uleb128 (p, &p);
+                               int clause_type;
+                               if (ctx->data_version > 12)
+                                       clause_type = *p++;
+                               else
+                                       clause_type = decode_uleb128 (p, &p);
                                int clause_num = decode_uleb128 (p, &p);
                                int64_t ptrdiff = decode_sleb128 (p, &p);
                                method_base += ptrdiff;
@@ -2739,7 +2784,7 @@ decode_buffer (ProfContext *ctx)
                                        throw_count++;
                                if (has_bt) {
                                        has_bt = 8;
-                                       frames = decode_bt (sframes, &has_bt, p, &p, ptr_base);
+                                       frames = decode_bt (ctx, sframes, &has_bt, p, &p, ptr_base, &method_base);
                                        if (!frames) {
                                                fprintf (outfile, "Cannot load backtrace\n");
                                                return 0;
@@ -2763,7 +2808,11 @@ decode_buffer (ProfContext *ctx)
                        LOG_TIME (time_base, tdiff);
                        time_base += tdiff;
                        if (subtype == TYPE_JITHELPER) {
-                               int type = decode_uleb128 (p, &p);
+                               int type;
+                               if (ctx->data_version > 12)
+                                       type = *p++;
+                               else
+                                       type = decode_uleb128 (p, &p);
                                intptr_t codediff = decode_sleb128 (p, &p);
                                int codelen = decode_uleb128 (p, &p);
                                const char *name;
@@ -2785,8 +2834,18 @@ decode_buffer (ProfContext *ctx)
                        int subtype = *p & 0xf0;
                        if (subtype == TYPE_SAMPLE_HIT) {
                                int i;
-                               int sample_type = decode_uleb128 (p + 1, &p);
-                               uint64_t tstamp = decode_uleb128 (p, &p);
+                               int sample_type;
+                               uint64_t tstamp;
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       sample_type = *p++;
+                                       tstamp = time_base;
+                               } else {
+                                       sample_type = decode_uleb128 (p + 1, &p);
+                                       tstamp = decode_uleb128 (p, &p);
+                               }
                                void *tid = (void *) thread_id;
                                if (ctx->data_version > 10)
                                        tid = (void *) (ptr_base + decode_sleb128 (p, &p));
@@ -2803,17 +2862,26 @@ decode_buffer (ProfContext *ctx)
                                        for (i = 0; i < count; ++i) {
                                                MethodDesc *method;
                                                int64_t ptrdiff = decode_sleb128 (p, &p);
-                                               int il_offset = decode_sleb128 (p, &p);
-                                               int native_offset = decode_sleb128 (p, &p);
                                                method_base += ptrdiff;
                                                method = lookup_method (method_base);
                                                if (debug)
-                                                       fprintf (outfile, "sample hit bt %d: %s at IL offset %d (native: %d)\n", i, method->name, il_offset, native_offset);
+                                                       fprintf (outfile, "sample hit bt %d: %s\n", i, method->name);
+                                               if (ctx->data_version < 13) {
+                                                       decode_sleb128 (p, &p); /* il offset */
+                                                       decode_sleb128 (p, &p); /* native offset */
+                                               }
                                        }
                                }
                        } else if (subtype == TYPE_SAMPLE_USYM) {
                                /* un unmanaged symbol description */
-                               uintptr_t addr = ptr_base + decode_sleb128 (p + 1, &p);
+                               uintptr_t addr;
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       addr = ptr_base + decode_sleb128 (p, &p);
+                               } else
+                                       addr = ptr_base + decode_sleb128 (p + 1, &p);
                                uintptr_t size = decode_uleb128 (p, &p);
                                char *name;
                                name = pstrdup ((char*)p);
@@ -2838,7 +2906,14 @@ decode_buffer (ProfContext *ctx)
                                while (*p) p++;
                                p++;
                        } else if (subtype == TYPE_SAMPLE_COUNTERS_DESC) {
-                               uint64_t i, len = decode_uleb128 (p + 1, &p);
+                               uint64_t i, len;
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       len = decode_uleb128 (p, &p);
+                               } else
+                                       len = decode_uleb128 (p + 1, &p);
                                for (i = 0; i < len; i++) {
                                        uint64_t type, unit, variance, index;
                                        uint64_t section = decode_uleb128 (p, &p);
@@ -2851,9 +2926,15 @@ decode_buffer (ProfContext *ctx)
                                        }
                                        name = pstrdup ((char*)p);
                                        while (*p++);
-                                       type = decode_uleb128 (p, &p);
-                                       unit = decode_uleb128 (p, &p);
-                                       variance = decode_uleb128 (p, &p);
+                                       if (ctx->data_version > 12) {
+                                               type = *p++;
+                                               unit = *p++;
+                                               variance = *p++;
+                                       } else {
+                                               type = decode_uleb128 (p, &p);
+                                               unit = decode_uleb128 (p, &p);
+                                               variance = decode_uleb128 (p, &p);
+                                       }
                                        index = decode_uleb128 (p, &p);
                                        add_counter (section_str, name, (int)type, (int)unit, (int)variance, (int)index);
                                }
@@ -2861,7 +2942,14 @@ decode_buffer (ProfContext *ctx)
                                int i;
                                CounterValue *value, *previous = NULL;
                                CounterList *list;
-                               uint64_t timestamp = decode_uleb128 (p + 1, &p);
+                               uint64_t timestamp; // milliseconds since startup
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       timestamp = (time_base - startup_time) / 1000 / 1000;
+                               } else
+                                       timestamp = decode_uleb128 (p + 1, &p);
                                uint64_t time_between = timestamp / 1000 * 1000 * 1000 * 1000 + startup_time;
                                while (1) {
                                        uint64_t type, index = decode_uleb128 (p, &p);
@@ -2875,7 +2963,10 @@ decode_buffer (ProfContext *ctx)
                                                }
                                        }
 
-                                       type = decode_uleb128 (p, &p);
+                                       if (ctx->data_version > 12)
+                                               type = *p++;
+                                       else
+                                               type = decode_uleb128 (p, &p);
 
                                        value = (CounterValue *)calloc (1, sizeof (CounterValue));
                                        value->timestamp = timestamp;
@@ -2939,6 +3030,13 @@ decode_buffer (ProfContext *ctx)
                                int token, n_offsets, method_id;
 
                                p++;
+
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                               }
+
                                assembly = (const char *)p; while (*p) p++; p++;
                                klass = (const char *)p; while (*p) p++; p++;
                                name = (const char *)p; while (*p) p++; p++;
@@ -2968,6 +3066,13 @@ decode_buffer (ProfContext *ctx)
                                int offset, count, line, column, method_id;
 
                                p++;
+
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                               }
+
                                method_id = decode_uleb128 (p, &p);
                                offset = decode_uleb128 (p, &p);
                                count = decode_uleb128 (p, &p);
@@ -2989,6 +3094,12 @@ decode_buffer (ProfContext *ctx)
                                int number_of_methods, fully_covered, partially_covered;
                                p++;
 
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                               }
+
                                name = (char *)p; while (*p) p++; p++;
                                guid = (char *)p; while (*p) p++; p++;
                                filename = (char *)p; while (*p) p++; p++;
@@ -3012,6 +3123,12 @@ decode_buffer (ProfContext *ctx)
                                int number_of_methods, fully_covered, partially_covered;
                                p++;
 
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                               }
+
                                assembly_name = (char *)p; while (*p) p++; p++;
                                class_name = (char *)p; while (*p) p++; p++;
                                number_of_methods = decode_uleb128 (p, &p);
@@ -3033,6 +3150,18 @@ decode_buffer (ProfContext *ctx)
                        }
                        break;
                }
+               case TYPE_META: {
+                       int subtype = *p & 0xf0;
+                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                       LOG_TIME (time_base, tdiff);
+                       time_base += tdiff;
+                       if (subtype == TYPE_SYNC_POINT) {
+                               int type = *p++;
+                               if (debug)
+                                       fprintf (outfile, "sync point %i (%s)\n", type, sync_point_name (type));
+                       }
+                       break;
+               }
                default:
                        fprintf (outfile, "unhandled profiler event: 0x%x at file offset: %llu + %lld (len: %d\n)\n", *p, (unsigned long long) file_offset, (long long) (p - ctx->buf), len);
                        exit (1);
@@ -3151,7 +3280,9 @@ dump_threads (ProfContext *ctx)
        ThreadContext *thread;
        fprintf (outfile, "\nThread summary\n");
        for (thread = ctx->threads; thread; thread = thread->next) {
-               fprintf (outfile, "\tThread: %p, name: \"%s\"\n", (void*)thread->thread_id, thread->name? thread->name: "");
+               if (thread->thread_id) {
+                       fprintf (outfile, "\tThread: %p, name: \"%s\"\n", (void*)thread->thread_id, thread->name? thread->name: "");
+               }
        }
 }
 
@@ -3790,6 +3921,8 @@ dump_stats (void)
        DUMP_EVENT_STAT (TYPE_COVERAGE, TYPE_COVERAGE_METHOD);
        DUMP_EVENT_STAT (TYPE_COVERAGE, TYPE_COVERAGE_STATEMENT);
        DUMP_EVENT_STAT (TYPE_COVERAGE, TYPE_COVERAGE_CLASS);
+
+       DUMP_EVENT_STAT (TYPE_META, TYPE_SYNC_POINT);
 }