[sgen] Move `sgen_safe_name()` to client code.
[mono.git] / mono / metadata / sgen-debug.c
index e084b5ffee18b1f26e6a1b76f10abb3cb8a57a1f..5c604b2a7d338d7b6f509f33131216d365755b21 100644 (file)
@@ -32,6 +32,7 @@
 #include "metadata/sgen-protocol.h"
 #include "metadata/sgen-memory-governor.h"
 #include "metadata/sgen-pinning.h"
+#include "metadata/sgen-client.h"
 #include "metadata/threadpool-internals.h"
 
 #define LOAD_VTABLE    SGEN_LOAD_VTABLE
@@ -51,13 +52,13 @@ void check_object (char *start);
 
 const char*descriptor_types [] = {
        "INVALID",
-       "run_length",
-       "small_bitmap",
+       "run length",
+       "bitmap",
+       "small pointer-free",
        "complex",
        "vector",
-       "large_bitmap",
-       "complex_arr",
-       "complex_ptrfree"
+       "complex arrray",
+       "complex pointer-free"
 };
 
 static char* describe_nursery_ptr (char *ptr, gboolean need_setup);
@@ -126,12 +127,12 @@ describe_pointer (char *ptr, gboolean need_setup)
                printf ("VTable is invalid (points inside nursery).\n");
                goto bridge;
        }
-       printf ("Class: %s\n", vtable->klass->name);
+       printf ("Class: %s.%s\n", vtable->klass->name_space, vtable->klass->name);
 
        desc = ((GCVTable*)vtable)->desc;
        printf ("Descriptor: %lx\n", (long)desc);
 
-       type = desc & 0x7;
+       type = desc & DESC_TYPE_MASK;
        printf ("Descriptor type: %d (%s)\n", type, descriptor_types [type]);
 
        size = sgen_safe_object_get_size ((MonoObject*)ptr);
@@ -160,7 +161,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;                                                                 \
                }                                                                                                                               \
@@ -174,7 +175,8 @@ static gboolean missing_remsets;
 static void
 check_consistency_callback (char *start, size_t size, void *dummy)
 {
-       GCVTable *vt = (GCVTable*)LOAD_VTABLE (start);
+       MonoVTable *vt = (MonoVTable*)LOAD_VTABLE (start);
+       mword desc = sgen_vtable_get_descriptor (vt);
        SGEN_LOG (8, "Scanning object %p, vtable: %p (%s)", start, vt, vt->klass->name);
 
 #include "sgen-scan-object.h"
@@ -220,7 +222,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;                         \
                }                                                                                                                               \
        }                                                                                                                                       \
@@ -230,7 +232,8 @@ static void
 check_mod_union_callback (char *start, size_t size, void *dummy)
 {
        gboolean in_los = (gboolean) (size_t) dummy;
-       GCVTable *vt = (GCVTable*)LOAD_VTABLE (start);
+       MonoVTable *vt = (MonoVTable*)LOAD_VTABLE (start);
+       mword desc = sgen_vtable_get_descriptor (vt);
        guint8 *cards;
        SGEN_LOG (8, "Scanning object %p, vtable: %p (%s)", start, vt, vt->klass->name);
 
@@ -269,6 +272,8 @@ sgen_check_mod_union_consistency (void)
 static void
 check_major_refs_callback (char *start, size_t size, void *dummy)
 {
+       mword desc = sgen_obj_get_descriptor (start);
+
 #include "sgen-scan-object.h"
 }
 
@@ -283,7 +288,7 @@ sgen_check_major_refs (void)
 #undef HANDLE_PTR
 #define HANDLE_PTR(ptr,obj)    do {    \
                if (*(ptr)) {   \
-                       g_assert (sgen_safe_name (*(ptr)) != NULL);     \
+                       g_assert (sgen_client_object_safe_name (*(ptr)) != NULL);       \
                }       \
        } while (0)
 
@@ -296,9 +301,13 @@ sgen_check_major_refs (void)
 void
 check_object (char *start)
 {
+       mword desc;
+
        if (!start)
                return;
 
+       desc = sgen_obj_get_descriptor (start);
+
 #include "sgen-scan-object.h"
 }
 
@@ -340,6 +349,16 @@ find_object_in_nursery_dump (char *object)
        return FALSE;
 }
 
+static void
+iterate_valid_nursery_objects (IterateObjectCallbackFunc callback, void *data)
+{
+       int i;
+       for (i = 0; i < valid_nursery_object_count; ++i) {
+               char *obj = valid_nursery_objects [i];
+               callback (obj, safe_object_get_size ((MonoObject*)obj), data);
+       }
+}
+
 static char*
 describe_nursery_ptr (char *ptr, gboolean need_setup)
 {
@@ -348,20 +367,20 @@ describe_nursery_ptr (char *ptr, gboolean need_setup)
        if (need_setup)
                setup_valid_nursery_objects ();
 
-       for (i = 0; i < valid_nursery_object_count; ++i) {
-               if (valid_nursery_objects [i] >= ptr)
+       for (i = 0; i < valid_nursery_object_count - 1; ++i) {
+               if (valid_nursery_objects [i + 1] > ptr)
                        break;
        }
 
        if (i >= valid_nursery_object_count || valid_nursery_objects [i] + safe_object_get_size ((MonoObject *)valid_nursery_objects [i]) < ptr) {
-               SGEN_LOG (0, "nursery-ptr (unalloc'd-memory)\n");
+               SGEN_LOG (0, "nursery-ptr (unalloc'd-memory)");
                return NULL;
        } else {
                char *obj = valid_nursery_objects [i];
                if (obj == ptr)
-                       SGEN_LOG (0, "nursery-ptr\n");
+                       SGEN_LOG (0, "nursery-ptr %p", obj);
                else
-                       SGEN_LOG (0, "nursery-ptr (interior-ptr offset %td)\n", ptr - obj);
+                       SGEN_LOG (0, "nursery-ptr %p (interior-ptr offset %td)", obj, ptr - obj);
                return obj;
        }
 }
@@ -425,6 +444,7 @@ static void
 verify_object_pointers_callback (char *start, size_t size, void *data)
 {
        gboolean allow_missing_pinned = (gboolean) (size_t) data;
+       mword desc = sgen_obj_get_descriptor (start);
 
 #include "sgen-scan-object.h"
 }
@@ -531,15 +551,14 @@ find_pinning_reference (char *obj, size_t size)
 #define HANDLE_PTR(ptr,obj)    do {                                    \
                char* __target = *(char**)ptr;                          \
                if (__target) {                                         \
-                       g_assert (is_valid_object_pointer (__target));  \
                        if (sgen_ptr_in_nursery (__target)) {           \
-                               g_assert (SGEN_OBJECT_IS_PINNED (__target)); \
-                       } else if (sgen_los_is_valid_object (__target)) { \
-                               g_assert (sgen_los_object_is_pinned (__target)); \
-                       } else if (major_collector.is_valid_object (__target)) { \
-                               g_assert (major_collector.is_object_live (__target)); \
+                               g_assert (!SGEN_OBJECT_IS_FORWARDED (__target)); \
                        } else {                                        \
-                               g_assert_not_reached ();                \
+                               mword __size = sgen_safe_object_get_size ((MonoObject*)__target); \
+                               if (__size <= SGEN_MAX_SMALL_OBJ_SIZE)  \
+                                       g_assert (major_collector.is_object_live (__target)); \
+                               else                                    \
+                                       g_assert (sgen_los_object_is_pinned (__target)); \
                        }                                               \
                }                                                       \
        } while (0)
@@ -547,9 +566,13 @@ find_pinning_reference (char *obj, size_t size)
 static void
 check_marked_callback (char *start, size_t size, void *dummy)
 {
-       gboolean is_los = (gboolean) (size_t) dummy;
+       gboolean flag = (gboolean) (size_t) dummy;
+       mword desc;
 
-       if (is_los) {
+       if (sgen_ptr_in_nursery (start)) {
+               if (flag)
+                       SGEN_ASSERT (0, SGEN_OBJECT_IS_PINNED (start), "All objects remaining in the nursery must be pinned");
+       } else if (flag) {
                if (!sgen_los_object_is_pinned (start))
                        return;
        } else {
@@ -557,14 +580,17 @@ check_marked_callback (char *start, size_t size, void *dummy)
                        return;
        }
 
+       desc = sgen_obj_get_descriptor_safe (start);
+
 #include "sgen-scan-object.h"
 }
 
 void
-sgen_check_major_heap_marked (void)
+sgen_check_heap_marked (gboolean nursery_must_be_pinned)
 {
        setup_valid_nursery_objects ();
 
+       iterate_valid_nursery_objects (check_marked_callback, (void*)(size_t)nursery_must_be_pinned);
        major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, check_marked_callback, (void*)FALSE);
        sgen_los_iterate_objects (check_marked_callback, (void*)TRUE);
 }
@@ -595,7 +621,7 @@ static gboolean scan_object_for_specific_ref_precise = TRUE;
 #define HANDLE_PTR(ptr,obj) do {               \
        if ((MonoObject*)*(ptr) == key) {       \
        g_print ("found ref to %p in object %p (%s) at offset %td\n",   \
-                       key, (obj), sgen_safe_name ((obj)), ((char*)(ptr) - (char*)(obj))); \
+                       key, (obj), sgen_client_object_safe_name ((MonoObject*)(obj)), ((char*)(ptr) - (char*)(obj))); \
        }                                                               \
        } while (0)
 
@@ -608,6 +634,7 @@ scan_object_for_specific_ref (char *start, MonoObject *key)
                start = forwarded;
 
        if (scan_object_for_specific_ref_precise) {
+               mword desc = sgen_obj_get_descriptor_safe (start);
                #include "sgen-scan-object.h"
        } else {
                mword *words = (mword*)start;
@@ -616,7 +643,7 @@ scan_object_for_specific_ref (char *start, MonoObject *key)
                for (i = 0; i < size / sizeof (mword); ++i) {
                        if (words [i] == (mword)key) {
                                g_print ("found possible ref to %p in object %p (%s) at offset %td\n",
-                                               key, start, sgen_safe_name (start), i * sizeof (mword));
+                                               key, start, sgen_client_object_safe_name ((MonoObject*)start), i * sizeof (mword));
                        }
                }
        }
@@ -640,7 +667,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 +696,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 +714,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 +762,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 +795,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 +813,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 +831,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 +880,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;
@@ -889,7 +923,9 @@ check_reference_for_xdomain (gpointer *ptr, char *obj, MonoDomain *domain)
 static void
 scan_object_for_xdomain_refs (char *start, mword size, void *data)
 {
-       MonoDomain *domain = ((MonoObject*)start)->vtable->domain;
+       MonoVTable *vt = (MonoVTable*)SGEN_LOAD_VTABLE (start);
+       MonoDomain *domain = vt->domain;
+       mword desc = sgen_vtable_get_descriptor (vt);
 
        #include "sgen-scan-object.h"
 }
@@ -908,6 +944,147 @@ sgen_check_for_xdomain_refs (void)
                scan_object_for_xdomain_refs (bigobj->data, sgen_los_object_size (bigobj), NULL);
 }
 
+/* If not null, dump the heap after each collection into this file */
+static FILE *heap_dump_file = NULL;
+
+void
+sgen_dump_occupied (char *start, char *end, char *section_start)
+{
+       fprintf (heap_dump_file, "<occupied offset=\"%td\" size=\"%td\"/>\n", start - section_start, end - start);
+}
+
+void
+sgen_dump_section (GCMemSection *section, const char *type)
+{
+       char *start = section->data;
+       char *end = section->data + section->size;
+       char *occ_start = NULL;
+       GCVTable *vt;
+       char *old_start G_GNUC_UNUSED = NULL; /* just for debugging */
+
+       fprintf (heap_dump_file, "<section type=\"%s\" size=\"%lu\">\n", type, (unsigned long)section->size);
+
+       while (start < end) {
+               guint size;
+               MonoClass *class G_GNUC_UNUSED;
+
+               if (!*(void**)start) {
+                       if (occ_start) {
+                               sgen_dump_occupied (occ_start, start, section->data);
+                               occ_start = NULL;
+                       }
+                       start += sizeof (void*); /* should be ALLOC_ALIGN, really */
+                       continue;
+               }
+               g_assert (start < section->next_data);
+
+               if (!occ_start)
+                       occ_start = start;
+
+               vt = (GCVTable*)LOAD_VTABLE (start);
+               class = vt->klass;
+
+               size = SGEN_ALIGN_UP (safe_object_get_size ((MonoObject*) start));
+
+               /*
+               fprintf (heap_dump_file, "<object offset=\"%d\" class=\"%s.%s\" size=\"%d\"/>\n",
+                               start - section->data,
+                               vt->klass->name_space, vt->klass->name,
+                               size);
+               */
+
+               old_start = start;
+               start += size;
+       }
+       if (occ_start)
+               sgen_dump_occupied (occ_start, start, section->data);
+
+       fprintf (heap_dump_file, "</section>\n");
+}
+
+static void
+dump_object (MonoObject *obj, gboolean dump_location)
+{
+       static char class_name [1024];
+
+       MonoClass *class = mono_object_class (obj);
+       int i, j;
+
+       /*
+        * Python's XML parser is too stupid to parse angle brackets
+        * in strings, so we just ignore them;
+        */
+       i = j = 0;
+       while (class->name [i] && j < sizeof (class_name) - 1) {
+               if (!strchr ("<>\"", class->name [i]))
+                       class_name [j++] = class->name [i];
+               ++i;
+       }
+       g_assert (j < sizeof (class_name));
+       class_name [j] = 0;
+
+       fprintf (heap_dump_file, "<object class=\"%s.%s\" size=\"%zd\"",
+                       class->name_space, class_name,
+                       safe_object_get_size (obj));
+       if (dump_location) {
+               const char *location;
+               if (sgen_ptr_in_nursery (obj))
+                       location = "nursery";
+               else if (safe_object_get_size (obj) <= SGEN_MAX_SMALL_OBJ_SIZE)
+                       location = "major";
+               else
+                       location = "LOS";
+               fprintf (heap_dump_file, " location=\"%s\"", location);
+       }
+       fprintf (heap_dump_file, "/>\n");
+}
+
+void
+sgen_debug_enable_heap_dump (const char *filename)
+{
+       heap_dump_file = fopen (filename, "w");
+       if (heap_dump_file) {
+               fprintf (heap_dump_file, "<sgen-dump>\n");
+               sgen_pin_stats_enable ();
+       }
+}
+
+void
+sgen_debug_dump_heap (const char *type, int num, const char *reason)
+{
+       ObjectList *list;
+       LOSObject *bigobj;
+
+       if (!heap_dump_file)
+               return;
+
+       fprintf (heap_dump_file, "<collection type=\"%s\" num=\"%d\"", type, num);
+       if (reason)
+               fprintf (heap_dump_file, " reason=\"%s\"", reason);
+       fprintf (heap_dump_file, ">\n");
+       fprintf (heap_dump_file, "<other-mem-usage type=\"mempools\" size=\"%ld\"/>\n", mono_mempool_get_bytes_allocated ());
+       sgen_dump_internal_mem_usage (heap_dump_file);
+       fprintf (heap_dump_file, "<pinned type=\"stack\" bytes=\"%zu\"/>\n", sgen_pin_stats_get_pinned_byte_count (PIN_TYPE_STACK));
+       /* fprintf (heap_dump_file, "<pinned type=\"static-data\" bytes=\"%d\"/>\n", pinned_byte_counts [PIN_TYPE_STATIC_DATA]); */
+       fprintf (heap_dump_file, "<pinned type=\"other\" bytes=\"%zu\"/>\n", sgen_pin_stats_get_pinned_byte_count (PIN_TYPE_OTHER));
+
+       fprintf (heap_dump_file, "<pinned-objects>\n");
+       for (list = sgen_pin_stats_get_object_list (); list; list = list->next)
+               dump_object (list->obj, TRUE);
+       fprintf (heap_dump_file, "</pinned-objects>\n");
+
+       sgen_dump_section (nursery_section, "nursery");
+
+       major_collector.dump_heap (heap_dump_file);
+
+       fprintf (heap_dump_file, "<los>\n");
+       for (bigobj = los_object_list; bigobj; bigobj = bigobj->next)
+               dump_object ((MonoObject*)bigobj->data, FALSE);
+       fprintf (heap_dump_file, "</los>\n");
+
+       fprintf (heap_dump_file, "</collection>\n");
+}
+
 static int
 compare_xrefs (const void *a_ptr, const void *b_ptr)
 {
@@ -927,6 +1104,7 @@ compare_xrefs (const void *a_ptr, const void *b_ptr)
        return 0;
 }
 
+/*
 static void
 dump_processor_state (SgenBridgeProcessor *p)
 {
@@ -951,6 +1129,7 @@ dump_processor_state (SgenBridgeProcessor *p)
 
        printf ("-------\n");
 }
+*/
 
 gboolean
 sgen_compare_bridge_processor_results (SgenBridgeProcessor *a, SgenBridgeProcessor *b)
@@ -1067,4 +1246,43 @@ sgen_compare_bridge_processor_results (SgenBridgeProcessor *a, SgenBridgeProcess
        return TRUE;
 }
 
+static char *found_obj;
+
+static void
+find_object_for_ptr_callback (char *obj, size_t size, void *user_data)
+{
+       char *ptr = user_data;
+
+       if (ptr >= obj && ptr < obj + size) {
+               g_assert (!found_obj);
+               found_obj = obj;
+       }
+}
+
+/* for use in the debugger */
+char*
+sgen_find_object_for_ptr (char *ptr)
+{
+       if (ptr >= nursery_section->data && ptr < nursery_section->end_data) {
+               found_obj = NULL;
+               sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data,
+                               find_object_for_ptr_callback, ptr, TRUE);
+               if (found_obj)
+                       return found_obj;
+       }
+
+       found_obj = NULL;
+       sgen_los_iterate_objects (find_object_for_ptr_callback, ptr);
+       if (found_obj)
+               return found_obj;
+
+       /*
+        * Very inefficient, but this is debugging code, supposed to
+        * be called from gdb, so we don't care.
+        */
+       found_obj = NULL;
+       major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, find_object_for_ptr_callback, ptr);
+       return found_obj;
+}
+
 #endif /*HAVE_SGEN_GC*/