Merge pull request #1174 from rhapsodyn/patch-1
[mono.git] / mono / metadata / sgen-debug.c
index 7773fbe1d16992ee19e839b2925f26c58e3a2997..1387676c75858cb57b6c6a403fb0f00d78705c1e 100644 (file)
@@ -160,7 +160,7 @@ static gboolean missing_remsets;
        if (*(ptr) && sgen_ptr_in_nursery ((char*)*(ptr))) { \
                if (!sgen_get_remset ()->find_address ((char*)(ptr)) && !sgen_cement_lookup (*(ptr))) { \
                        SGEN_LOG (0, "Oldspace->newspace reference %p at offset %td in object %p (%s.%s) not found in remsets.", *(ptr), (char*)(ptr) - (char*)(obj), (obj), ((MonoObject*)(obj))->vtable->klass->name_space, ((MonoObject*)(obj))->vtable->klass->name); \
-                       binary_protocol_missing_remset ((obj), (gpointer)LOAD_VTABLE ((obj)), (char*)(ptr) - (char*)(obj), *(ptr), (gpointer)LOAD_VTABLE(*(ptr)), object_is_pinned (*(ptr))); \
+                       binary_protocol_missing_remset ((obj), (gpointer)LOAD_VTABLE ((obj)), (int) ((char*)(ptr) - (char*)(obj)), *(ptr), (gpointer)LOAD_VTABLE(*(ptr)), object_is_pinned (*(ptr))); \
                        if (!object_is_pinned (*(ptr)))                                                         \
                                missing_remsets = TRUE;                                                                 \
                }                                                                                                                               \
@@ -220,7 +220,7 @@ is_major_or_los_object_marked (char *obj)
        if (*(ptr) && !sgen_ptr_in_nursery ((char*)*(ptr)) && !is_major_or_los_object_marked ((char*)*(ptr))) { \
                if (!sgen_get_remset ()->find_address_with_cards (start, cards, (char*)(ptr))) { \
                        SGEN_LOG (0, "major->major reference %p at offset %td in object %p (%s.%s) not found in remsets.", *(ptr), (char*)(ptr) - (char*)(obj), (obj), ((MonoObject*)(obj))->vtable->klass->name_space, ((MonoObject*)(obj))->vtable->klass->name); \
-                       binary_protocol_missing_remset ((obj), (gpointer)LOAD_VTABLE ((obj)), (char*)(ptr) - (char*)(obj), *(ptr), (gpointer)LOAD_VTABLE(*(ptr)), object_is_pinned (*(ptr))); \
+                       binary_protocol_missing_remset ((obj), (gpointer)LOAD_VTABLE ((obj)), (int) ((char*)(ptr) - (char*)(obj)), *(ptr), (gpointer)LOAD_VTABLE(*(ptr)), object_is_pinned (*(ptr))); \
                        missing_remsets = TRUE;                         \
                }                                                                                                                               \
        }                                                                                                                                       \
@@ -640,7 +640,7 @@ static MonoObject *check_key = NULL;
 static RootRecord *check_root = NULL;
 
 static void
-check_root_obj_specific_ref_from_marker (void **obj)
+check_root_obj_specific_ref_from_marker (void **obj, void *gc_data)
 {
        check_root_obj_specific_ref (check_root, check_key, *obj);
 }
@@ -669,7 +669,7 @@ scan_roots_for_specific_ref (MonoObject *key, int root_type)
                        return;
                case ROOT_DESC_COMPLEX: {
                        gsize *bitmap_data = sgen_get_complex_descriptor_bitmap (desc);
-                       int bwords = (*bitmap_data) - 1;
+                       int bwords = (int) ((*bitmap_data) - 1);
                        void **start_run = start_root;
                        bitmap_data++;
                        while (bwords-- > 0) {
@@ -687,7 +687,7 @@ scan_roots_for_specific_ref (MonoObject *key, int root_type)
                }
                case ROOT_DESC_USER: {
                        MonoGCRootMarkFunc marker = sgen_get_user_descriptor_func (desc);
-                       marker (start_root, check_root_obj_specific_ref_from_marker);
+                       marker (start_root, check_root_obj_specific_ref_from_marker, NULL);
                        break;
                }
                case ROOT_DESC_RUN_LEN:
@@ -735,6 +735,13 @@ check_obj_not_in_domain (void **o)
        g_assert (((MonoObject*)(*o))->vtable->domain != check_domain);
 }
 
+
+static void
+check_obj_not_in_domain_callback (void **o, void *gc_data)
+{
+       g_assert (((MonoObject*)(*o))->vtable->domain != check_domain);
+}
+
 void
 sgen_scan_for_registered_roots_in_domain (MonoDomain *domain, int root_type)
 {
@@ -761,7 +768,7 @@ sgen_scan_for_registered_roots_in_domain (MonoDomain *domain, int root_type)
                        break;
                case ROOT_DESC_COMPLEX: {
                        gsize *bitmap_data = sgen_get_complex_descriptor_bitmap (desc);
-                       int bwords = (*bitmap_data) - 1;
+                       int bwords = (int)((*bitmap_data) - 1);
                        void **start_run = start_root;
                        bitmap_data++;
                        while (bwords-- > 0) {
@@ -779,7 +786,7 @@ sgen_scan_for_registered_roots_in_domain (MonoDomain *domain, int root_type)
                }
                case ROOT_DESC_USER: {
                        MonoGCRootMarkFunc marker = sgen_get_user_descriptor_func (desc);
-                       marker (start_root, check_obj_not_in_domain);
+                       marker (start_root, check_obj_not_in_domain_callback, NULL);
                        break;
                }
                case ROOT_DESC_RUN_LEN:
@@ -797,7 +804,7 @@ is_xdomain_ref_allowed (gpointer *ptr, char *obj, MonoDomain *domain)
 {
        MonoObject *o = (MonoObject*)(obj);
        MonoObject *ref = (MonoObject*)*(ptr);
-       int offset = (char*)(ptr) - (char*)o;
+       size_t offset = (char*)(ptr) - (char*)o;
 
        if (o->vtable->klass == mono_defaults.thread_class && offset == G_STRUCT_OFFSET (MonoThread, internal_thread))
                return TRUE;
@@ -846,7 +853,7 @@ check_reference_for_xdomain (gpointer *ptr, char *obj, MonoDomain *domain)
 {
        MonoObject *o = (MonoObject*)(obj);
        MonoObject *ref = (MonoObject*)*(ptr);
-       int offset = (char*)(ptr) - (char*)o;
+       size_t offset = (char*)(ptr) - (char*)o;
        MonoClass *class;
        MonoClassField *field;
        char *str;
@@ -908,4 +915,165 @@ sgen_check_for_xdomain_refs (void)
                scan_object_for_xdomain_refs (bigobj->data, sgen_los_object_size (bigobj), NULL);
 }
 
+static int
+compare_xrefs (const void *a_ptr, const void *b_ptr)
+{
+       const MonoGCBridgeXRef *a = a_ptr;
+       const MonoGCBridgeXRef *b = 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");
+}
+*/
+
+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) {
+                       MonoObject *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 = 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 = 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 = sgen_alloc_internal_dynamic (xrefs_alloc_size, INTERNAL_MEM_BRIDGE_DEBUG, TRUE);
+       b_xrefs = 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 = 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 = 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;
+}
+
 #endif /*HAVE_SGEN_GC*/