[runtime] Coverage profiler fixes (#5698)
[mono.git] / mono / profiler / coverage.c
index 5a9d5b69c4fa0f2083f23df6bd06ef3344dd03f9..f88e49df626f33be6d8f9f94b36ad52d4e44ef8d 100644 (file)
@@ -47,8 +47,7 @@
  *                 - token
  *   <statement> - Contains data about IL statements. Has no child elements
  *                 Attributes:
- *                    - offset: The offset of the statement in the IL code after the previous
- *                              statement's offset
+ *                    - offset: The offset of the statement in the IL code
  *                    - counter: 1 if the line was covered, 0 if it was not
  *                    - line: The line number in the parent method's file
  *                    - column: The column on the line
@@ -113,6 +112,8 @@ struct _MonoProfiler {
 
        MonoConcurrentHashTable *image_to_methods;
 
+       GHashTable *uncovered_methods;
+
        guint32 previous_offset;
 };
 
@@ -200,12 +201,11 @@ obtain_coverage_for_method (MonoProfiler *prof, const MonoProfilerCoverageData *
 {
        g_assert (prof == &coverage_profiler);
 
-       int offset = entry->il_offset - coverage_profiler.previous_offset;
        CoverageEntry *e = g_new (CoverageEntry, 1);
 
        coverage_profiler.previous_offset = entry->il_offset;
 
-       e->offset = offset;
+       e->offset = entry->il_offset;
        e->counter = entry->counter;
        e->filename = g_strdup(entry->file_name ? entry->file_name : "");
        e->line = entry->line;
@@ -359,7 +359,30 @@ dump_classes_for_image (gpointer key, gpointer value, gpointer userdata)
        class_name = mono_type_get_name (mono_class_get_type (klass));
 
        number_of_methods = mono_class_num_methods (klass);
-       fully_covered = count_queue (class_methods);
+
+       GHashTable *covered_methods = g_hash_table_new (NULL, NULL);
+       int count = 0;
+       {
+               MonoLockFreeQueueNode *node;
+               guint count = 0;
+
+               while ((node = mono_lock_free_queue_dequeue (class_methods))) {
+                       MethodNode *mnode = (MethodNode*)node;
+                       g_hash_table_insert (covered_methods, mnode->method, mnode->method);
+                       count++;
+                       mono_thread_hazardous_try_free (node, g_free);
+               }
+       }
+       fully_covered = count;
+
+       gpointer iter = NULL;
+       MonoMethod *method;
+       while ((method = mono_class_get_methods (klass, &iter))) {
+               if (!g_hash_table_lookup (covered_methods, method))
+                       g_hash_table_insert (coverage_profiler.uncovered_methods, method, method);
+       }
+       g_hash_table_destroy (covered_methods);
+
        /* We don't handle partial covered yet */
        partially_covered = 0;
 
@@ -430,6 +453,7 @@ dump_coverage (void)
        mono_os_mutex_lock (&coverage_profiler.mutex);
        mono_conc_hashtable_foreach (coverage_profiler.assemblies, dump_assembly, NULL);
        mono_conc_hashtable_foreach (coverage_profiler.methods, dump_method, NULL);
+       g_hash_table_foreach (coverage_profiler.uncovered_methods, dump_method, NULL);
        mono_os_mutex_unlock (&coverage_profiler.mutex);
 
        fprintf (coverage_profiler.file, "</coverage>\n");
@@ -903,6 +927,7 @@ mono_profiler_init_coverage (const char *desc)
        coverage_profiler.classes = mono_conc_hashtable_new (NULL, NULL);
        coverage_profiler.filtered_classes = mono_conc_hashtable_new (NULL, NULL);
        coverage_profiler.image_to_methods = mono_conc_hashtable_new (NULL, NULL);
+       coverage_profiler.uncovered_methods = g_hash_table_new (NULL, NULL);
        init_suppressed_assemblies ();
 
        coverage_profiler.filters = filters;