#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
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);
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);
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"
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);
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"
}
#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)
void
check_object (char *start)
{
+ mword desc;
+
if (!start)
return;
+ desc = sgen_obj_get_descriptor (start);
+
#include "sgen-scan-object.h"
}
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)
{
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;
}
}
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"
}
#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)
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 {
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);
}
#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)
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;
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));
}
}
}
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"
}
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)
{
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*/