Merge pull request #2609 from directhex/xambug-30902
[mono.git] / mono / metadata / sgen-bridge.c
index 4d7dd6f4bfe3bcb2bc07cf5e47f94b9e0b118c89..5e4fa165ab0efc72fd2d09482953ab52b8ee1289 100644 (file)
 
 #include <stdlib.h>
 
-#include "sgen-gc.h"
-#include "sgen-bridge.h"
-#include "sgen-hash-table.h"
-#include "sgen-qsort.h"
-#include "utils/mono-logger-internal.h"
-#include "utils/mono-time.h"
-#include "utils/mono-compiler.h"
+#include "sgen/sgen-gc.h"
+#include "sgen-bridge-internals.h"
+#include "sgen/sgen-hash-table.h"
+#include "sgen/sgen-qsort.h"
+#include "utils/mono-logger-internals.h"
 
 MonoGCBridgeCallbacks bridge_callbacks;
 static SgenBridgeProcessor bridge_processor;
 static SgenBridgeProcessor compare_to_bridge_processor;
 
-gboolean bridge_processing_in_progress = FALSE;
+volatile gboolean bridge_processing_in_progress = FALSE;
 
 void
 mono_gc_wait_for_bridge_processing (void)
@@ -108,7 +106,7 @@ sgen_set_bridge_implementation (const char *name)
 }
 
 gboolean
-sgen_is_bridge_object (MonoObject *obj)
+sgen_is_bridge_object (GCObject *obj)
 {
        if ((obj->vtable->gc_bits & SGEN_GC_BIT_BRIDGE_OBJECT) != SGEN_GC_BIT_BRIDGE_OBJECT)
                return FALSE;
@@ -150,14 +148,14 @@ sgen_bridge_processing_stw_step (void)
                compare_to_bridge_processor.processing_stw_step ();
 }
 
-static mono_bool
-is_bridge_object_alive (MonoObject *obj, void *data)
+static gboolean
+is_bridge_object_dead (GCObject *obj, void *data)
 {
-       SgenHashTable *table = data;
-       unsigned char *value = sgen_hash_table_lookup (table, obj);
+       SgenHashTable *table = (SgenHashTable *)data;
+       unsigned char *value = (unsigned char *)sgen_hash_table_lookup (table, obj);
        if (!value)
-               return TRUE;
-       return *value;
+               return FALSE;
+       return !*value;
 }
 
 static void
@@ -181,9 +179,12 @@ null_weak_links_to_dead_objects (SgenBridgeProcessor *processor, int generation)
        }
 
        /* Null weak links to dead objects. */
-       sgen_null_links_with_predicate (GENERATION_NURSERY, is_bridge_object_alive, &alive_hash);
-       if (generation == GENERATION_OLD)
-               sgen_null_links_with_predicate (GENERATION_OLD, is_bridge_object_alive, &alive_hash);
+       sgen_null_links_if (is_bridge_object_dead, &alive_hash, GENERATION_NURSERY, FALSE);
+       sgen_null_links_if (is_bridge_object_dead, &alive_hash, GENERATION_NURSERY, TRUE);
+       if (generation == GENERATION_OLD) {
+               sgen_null_links_if (is_bridge_object_dead, &alive_hash, GENERATION_OLD, FALSE);
+               sgen_null_links_if (is_bridge_object_dead, &alive_hash, GENERATION_OLD, TRUE);
+       }
 
        sgen_hash_table_clean (&alive_hash);
 }
@@ -212,13 +213,170 @@ free_callback_data (SgenBridgeProcessor *processor)
        processor->api_xrefs = NULL;
 }
 
+static int
+compare_xrefs (const void *a_ptr, const void *b_ptr)
+{
+       const MonoGCBridgeXRef *a = (const MonoGCBridgeXRef *)a_ptr;
+       const MonoGCBridgeXRef *b = (const MonoGCBridgeXRef *)b_ptr;
+
+       if (a->src_scc_index < b->src_scc_index)
+               return -1;
+       if (a->src_scc_index > b->src_scc_index)
+               return 1;
+
+       if (a->dst_scc_index < b->dst_scc_index)
+               return -1;
+       if (a->dst_scc_index > b->dst_scc_index)
+               return 1;
+
+       return 0;
+}
+
+/*
+static void
+dump_processor_state (SgenBridgeProcessor *p)
+{
+       int i;
+
+       printf ("------\n");
+       printf ("SCCS %d\n", p->num_sccs);
+       for (i = 0; i < p->num_sccs; ++i) {
+               int j;
+               MonoGCBridgeSCC *scc = p->api_sccs [i];
+               printf ("\tSCC %d:", i);
+               for (j = 0; j < scc->num_objs; ++j) {
+                       MonoObject *obj = scc->objs [j];
+                       printf (" %p", obj);
+               }
+               printf ("\n");
+       }
+
+       printf ("XREFS %d\n", p->num_xrefs);
+       for (i = 0; i < p->num_xrefs; ++i)
+               printf ("\t%d -> %d\n", p->api_xrefs [i].src_scc_index, p->api_xrefs [i].dst_scc_index);
+
+       printf ("-------\n");
+}
+*/
+
+static gboolean
+sgen_compare_bridge_processor_results (SgenBridgeProcessor *a, SgenBridgeProcessor *b)
+{
+       int i;
+       SgenHashTable obj_to_a_scc = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_DEBUG, INTERNAL_MEM_BRIDGE_DEBUG, sizeof (int), mono_aligned_addr_hash, NULL);
+       SgenHashTable b_scc_to_a_scc = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_DEBUG, INTERNAL_MEM_BRIDGE_DEBUG, sizeof (int), g_direct_hash, NULL);
+       MonoGCBridgeXRef *a_xrefs, *b_xrefs;
+       size_t xrefs_alloc_size;
+
+       // dump_processor_state (a);
+       // dump_processor_state (b);
+
+       if (a->num_sccs != b->num_sccs)
+               g_error ("SCCS count expected %d but got %d", a->num_sccs, b->num_sccs);
+       if (a->num_xrefs != b->num_xrefs)
+               g_error ("SCCS count expected %d but got %d", a->num_xrefs, b->num_xrefs);
+
+       /*
+        * First we build a hash of each object in `a` to its respective SCC index within
+        * `a`.  Along the way we also assert that no object is more than one SCC.
+        */
+       for (i = 0; i < a->num_sccs; ++i) {
+               int j;
+               MonoGCBridgeSCC *scc = a->api_sccs [i];
+
+               g_assert (scc->num_objs > 0);
+
+               for (j = 0; j < scc->num_objs; ++j) {
+                       GCObject *obj = scc->objs [j];
+                       gboolean new_entry = sgen_hash_table_replace (&obj_to_a_scc, obj, &i, NULL);
+                       g_assert (new_entry);
+               }
+       }
+
+       /*
+        * Now we check whether each of the objects in `b` are in `a`, and whether the SCCs
+        * of `b` contain the same sets of objects as those of `a`.
+        *
+        * While we're doing this, build a hash table to map from `b` SCC indexes to `a` SCC
+        * indexes.
+        */
+       for (i = 0; i < b->num_sccs; ++i) {
+               MonoGCBridgeSCC *scc = b->api_sccs [i];
+               MonoGCBridgeSCC *a_scc;
+               int *a_scc_index_ptr;
+               int a_scc_index;
+               int j;
+               gboolean new_entry;
+
+               g_assert (scc->num_objs > 0);
+               a_scc_index_ptr = (int *)sgen_hash_table_lookup (&obj_to_a_scc, scc->objs [0]);
+               g_assert (a_scc_index_ptr);
+               a_scc_index = *a_scc_index_ptr;
+
+               //g_print ("A SCC %d -> B SCC %d\n", a_scc_index, i);
+
+               a_scc = a->api_sccs [a_scc_index];
+               g_assert (a_scc->num_objs == scc->num_objs);
+
+               for (j = 1; j < scc->num_objs; ++j) {
+                       a_scc_index_ptr = (int *)sgen_hash_table_lookup (&obj_to_a_scc, scc->objs [j]);
+                       g_assert (a_scc_index_ptr);
+                       g_assert (*a_scc_index_ptr == a_scc_index);
+               }
+
+               new_entry = sgen_hash_table_replace (&b_scc_to_a_scc, GINT_TO_POINTER (i), &a_scc_index, NULL);
+               g_assert (new_entry);
+       }
+
+       /*
+        * Finally, check that we have the same xrefs.  We do this by making copies of both
+        * xref arrays, and replacing the SCC indexes in the copy for `b` with the
+        * corresponding indexes in `a`.  Then we sort both arrays and assert that they're
+        * the same.
+        *
+        * At the same time, check that no xref is self-referential and that there are no
+        * duplicate ones.
+        */
+
+       xrefs_alloc_size = a->num_xrefs * sizeof (MonoGCBridgeXRef);
+       a_xrefs = (MonoGCBridgeXRef *)sgen_alloc_internal_dynamic (xrefs_alloc_size, INTERNAL_MEM_BRIDGE_DEBUG, TRUE);
+       b_xrefs = (MonoGCBridgeXRef *)sgen_alloc_internal_dynamic (xrefs_alloc_size, INTERNAL_MEM_BRIDGE_DEBUG, TRUE);
+
+       memcpy (a_xrefs, a->api_xrefs, xrefs_alloc_size);
+       for (i = 0; i < b->num_xrefs; ++i) {
+               MonoGCBridgeXRef *xref = &b->api_xrefs [i];
+               int *scc_index_ptr;
+
+               g_assert (xref->src_scc_index != xref->dst_scc_index);
+
+               scc_index_ptr = (int *)sgen_hash_table_lookup (&b_scc_to_a_scc, GINT_TO_POINTER (xref->src_scc_index));
+               g_assert (scc_index_ptr);
+               b_xrefs [i].src_scc_index = *scc_index_ptr;
+
+               scc_index_ptr = (int *)sgen_hash_table_lookup (&b_scc_to_a_scc, GINT_TO_POINTER (xref->dst_scc_index));
+               g_assert (scc_index_ptr);
+               b_xrefs [i].dst_scc_index = *scc_index_ptr;
+       }
+
+       qsort (a_xrefs, a->num_xrefs, sizeof (MonoGCBridgeXRef), compare_xrefs);
+       qsort (b_xrefs, a->num_xrefs, sizeof (MonoGCBridgeXRef), compare_xrefs);
+
+       for (i = 0; i < a->num_xrefs; ++i) {
+               g_assert (a_xrefs [i].src_scc_index == b_xrefs [i].src_scc_index);
+               g_assert (a_xrefs [i].dst_scc_index == b_xrefs [i].dst_scc_index);
+       }
+
+       sgen_hash_table_clean (&obj_to_a_scc);
+       sgen_hash_table_clean (&b_scc_to_a_scc);
+       sgen_free_internal_dynamic (a_xrefs, xrefs_alloc_size, INTERNAL_MEM_BRIDGE_DEBUG);
+       sgen_free_internal_dynamic (b_xrefs, xrefs_alloc_size, INTERNAL_MEM_BRIDGE_DEBUG);
+
+       return TRUE;
+}
+
 void
 sgen_bridge_processing_finish (int generation)
 {
-       unsigned long step_8;
-       SGEN_TV_DECLARE (atv);
-       SGEN_TV_DECLARE (btv);
-
        bridge_processor.processing_build_callback_data (generation);
        if (compare_bridge_processors ())
                compare_to_bridge_processor.processing_build_callback_data (generation);
@@ -234,17 +392,12 @@ sgen_bridge_processing_finish (int generation)
        if (compare_bridge_processors ())
                sgen_compare_bridge_processor_results (&bridge_processor, &compare_to_bridge_processor);
 
-       SGEN_TV_GETTIME (btv);
-
        null_weak_links_to_dead_objects (&bridge_processor, generation);
 
        free_callback_data (&bridge_processor);
        if (compare_bridge_processors ())
                free_callback_data (&compare_to_bridge_processor);
 
-       SGEN_TV_GETTIME (atv);
-       step_8 = SGEN_TV_ELAPSED (btv, atv);
-
  after_callback:
        bridge_processor.processing_after_callback (generation);
        if (compare_bridge_processors ())
@@ -254,13 +407,13 @@ sgen_bridge_processing_finish (int generation)
 }
 
 MonoGCBridgeObjectKind
-sgen_bridge_class_kind (MonoClass *class)
+sgen_bridge_class_kind (MonoClass *klass)
 {
-       return bridge_processor.class_kind (class);
+       return bridge_processor.class_kind (klass);
 }
 
 void
-sgen_bridge_register_finalized_object (MonoObject *obj)
+sgen_bridge_register_finalized_object (GCObject *obj)
 {
        bridge_processor.register_finalized_object (obj);
        if (compare_bridge_processors ())
@@ -268,7 +421,7 @@ sgen_bridge_register_finalized_object (MonoObject *obj)
 }
 
 void
-sgen_bridge_describe_pointer (MonoObject *obj)
+sgen_bridge_describe_pointer (GCObject *obj)
 {
        if (bridge_processor.describe_pointer)
                bridge_processor.describe_pointer (obj);
@@ -289,9 +442,9 @@ set_dump_prefix (const char *prefix)
 static const char *bridge_class;
 
 static MonoGCBridgeObjectKind
-bridge_test_bridge_class_kind (MonoClass *class)
+bridge_test_bridge_class_kind (MonoClass *klass)
 {
-       if (!strcmp (bridge_class, class->name))
+       if (!strcmp (bridge_class, klass->name))
                return GC_BRIDGE_TRANSPARENT_BRIDGE_CLASS;
        return GC_BRIDGE_TRANSPARENT_CLASS;
 }