X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fsgen-debug.c;h=a04e1a7c1f560aa67041e1fd8b73fe16bd1d4b62;hb=93f3bdf944f0d47a79d39b65af9dd151618a4fd0;hp=9102ede9054081e44571dbe776c0ad11addceac5;hpb=f6a5608f00d8051bb3a13437b69ed3e1ea55381c;p=mono.git diff --git a/mono/metadata/sgen-debug.c b/mono/metadata/sgen-debug.c index 9102ede9054..a04e1a7c1f5 100644 --- a/mono/metadata/sgen-debug.c +++ b/mono/metadata/sgen-debug.c @@ -8,25 +8,20 @@ * Copyright 2005-2011 Novell, Inc (http://www.novell.com) * Copyright 2011 Xamarin Inc (http://www.xamarin.com) * Copyright 2011 Xamarin, Inc. + * Copyright (C) 2012 Xamarin Inc * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License 2.0 as published by the Free Software Foundation; + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License 2.0 along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" @@ -34,9 +29,9 @@ #include "metadata/sgen-gc.h" #include "metadata/sgen-cardtable.h" -#include "metadata/sgen-ssb.h" #include "metadata/sgen-protocol.h" #include "metadata/sgen-memory-governor.h" +#include "metadata/sgen-pinning.h" #define LOAD_VTABLE SGEN_LOAD_VTABLE @@ -54,26 +49,35 @@ void check_object (char *start); */ const char*descriptor_types [] = { + "INVALID", "run_length", "small_bitmap", - "string", "complex", "vector", - "array", "large_bitmap", - "complex_arr" + "complex_arr", + "complex_ptrfree" }; -void -describe_ptr (char *ptr) +static char* describe_nursery_ptr (char *ptr, gboolean need_setup); + +static void +describe_pointer (char *ptr, gboolean need_setup) { MonoVTable *vtable; mword desc; int type; char *start; + char *forwarded; + mword size; + restart: if (sgen_ptr_in_nursery (ptr)) { - printf ("Pointer inside nursery.\n"); + start = describe_nursery_ptr (ptr, need_setup); + if (!start) + return; + ptr = start; + vtable = (MonoVTable*)LOAD_VTABLE (ptr); } else { if (sgen_ptr_is_in_los (ptr, &start)) { if (ptr == start) @@ -81,10 +85,22 @@ describe_ptr (char *ptr) else printf ("Pointer is at offset 0x%x of object %p in LOS space.\n", (int)(ptr - start), start); ptr = start; - } else if (major_collector.ptr_is_in_non_pinned_space (ptr)) { - printf ("Pointer inside oldspace.\n"); + mono_sgen_los_describe_pointer (ptr); + vtable = (MonoVTable*)LOAD_VTABLE (ptr); + } else if (major_collector.ptr_is_in_non_pinned_space (ptr, &start)) { + if (ptr == start) + printf ("Pointer is the start of object %p in oldspace.\n", start); + else if (start) + printf ("Pointer is at offset 0x%x of object %p in oldspace.\n", (int)(ptr - start), start); + else + printf ("Pointer inside oldspace.\n"); + if (start) + ptr = start; + vtable = major_collector.describe_pointer (ptr); } else if (major_collector.obj_is_from_pinned_alloc (ptr)) { + // FIXME: Handle pointers to the inside of objects printf ("Pointer is inside a pinned chunk.\n"); + vtable = (MonoVTable*)LOAD_VTABLE (ptr); } else { printf ("Pointer unknown.\n"); return; @@ -94,20 +110,20 @@ describe_ptr (char *ptr) if (object_is_pinned (ptr)) printf ("Object is pinned.\n"); - if (object_is_forwarded (ptr)) - printf ("Object is forwared.\n"); - - // FIXME: Handle pointers to the inside of objects - vtable = (MonoVTable*)LOAD_VTABLE (ptr); + if ((forwarded = object_is_forwarded (ptr))) { + printf ("Object is forwarded to %p:\n", forwarded); + ptr = forwarded; + goto restart; + } printf ("VTable: %p\n", vtable); if (vtable == NULL) { printf ("VTable is invalid (empty).\n"); - return; + goto bridge; } if (sgen_ptr_in_nursery (vtable)) { printf ("VTable is invalid (points inside nursery).\n"); - return; + goto bridge; } printf ("Class: %s\n", vtable->klass->name); @@ -116,6 +132,18 @@ describe_ptr (char *ptr) type = desc & 0x7; printf ("Descriptor type: %d (%s)\n", type, descriptor_types [type]); + + size = sgen_safe_object_get_size ((MonoObject*)ptr); + printf ("Size: %d\n", (int)size); + + bridge: + sgen_bridge_describe_pointer ((MonoObject*)ptr); +} + +void +describe_ptr (char *ptr) +{ + describe_pointer (ptr, TRUE); } static gboolean missing_remsets; @@ -130,7 +158,7 @@ static gboolean missing_remsets; #define HANDLE_PTR(ptr,obj) do { \ if (*(ptr) && sgen_ptr_in_nursery ((char*)*(ptr))) { \ if (!sgen_get_remset ()->find_address ((char*)(ptr))) { \ - fprintf (gc_debug_file, "Oldspace->newspace reference %p at offset %td in object %p (%s.%s) not found in remsets.\n", *(ptr), (char*)(ptr) - (char*)(obj), (obj), ((MonoObject*)(obj))->vtable->klass->name_space, ((MonoObject*)(obj))->vtable->klass->name); \ + 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))); \ if (!object_is_pinned (*(ptr))) \ missing_remsets = TRUE; \ @@ -146,9 +174,8 @@ static void check_consistency_callback (char *start, size_t size, void *dummy) { GCVTable *vt = (GCVTable*)LOAD_VTABLE (start); - DEBUG (8, fprintf (gc_debug_file, "Scanning object %p, vtable: %p (%s)\n", start, vt, vt->klass->name)); + SGEN_LOG (8, "Scanning object %p, vtable: %p (%s)", start, vt, vt->klass->name); -#define SCAN_OBJECT_ACTION #include "sgen-scan-object.h" } @@ -164,19 +191,72 @@ sgen_check_consistency (void) missing_remsets = FALSE; - DEBUG (1, fprintf (gc_debug_file, "Begin heap consistency check...\n")); + SGEN_LOG (1, "Begin heap consistency check..."); // Check that oldspace->newspace pointers are registered with the collector major_collector.iterate_objects (TRUE, TRUE, (IterateObjectCallbackFunc)check_consistency_callback, NULL); sgen_los_iterate_objects ((IterateObjectCallbackFunc)check_consistency_callback, NULL); - DEBUG (1, fprintf (gc_debug_file, "Heap consistency check done.\n")); + SGEN_LOG (1, "Heap consistency check done."); if (!binary_protocol_is_enabled ()) g_assert (!missing_remsets); } +static gboolean +is_major_or_los_object_marked (char *obj) +{ + if (sgen_safe_object_get_size ((MonoObject*)obj) > SGEN_MAX_SMALL_OBJ_SIZE) { + return sgen_los_object_is_pinned (obj); + } else { + return sgen_get_major_collector ()->is_object_live (obj); + } +} + +#undef HANDLE_PTR +#define HANDLE_PTR(ptr,obj) do { \ + 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))); \ + } \ + } \ + } while (0) + +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); + guint8 *cards; + SGEN_LOG (8, "Scanning object %p, vtable: %p (%s)", start, vt, vt->klass->name); + + if (!is_major_or_los_object_marked (start)) + return; + + if (in_los) + cards = sgen_los_header_for_object (start)->cardtable_mod_union; + else + cards = sgen_get_major_collector ()->get_cardtable_mod_union_for_object (start); + + SGEN_ASSERT (0, cards, "we must have mod union for marked major objects"); + +#include "sgen-scan-object.h" +} + +void +sgen_check_mod_union_consistency (void) +{ + missing_remsets = FALSE; + + major_collector.iterate_objects (TRUE, TRUE, (IterateObjectCallbackFunc)check_mod_union_callback, (void*)FALSE); + + sgen_los_iterate_objects ((IterateObjectCallbackFunc)check_mod_union_callback, (void*)TRUE); + + if (!binary_protocol_is_enabled ()) + g_assert (!missing_remsets); +} #undef HANDLE_PTR #define HANDLE_PTR(ptr,obj) do { \ @@ -187,7 +267,6 @@ sgen_check_consistency (void) static void check_major_refs_callback (char *start, size_t size, void *dummy) { -#define SCAN_OBJECT_ACTION #include "sgen-scan-object.h" } @@ -232,6 +311,15 @@ setup_mono_sgen_scan_area_with_callback (char *object, size_t size, void *data) valid_nursery_objects [valid_nursery_object_count++] = object; } +static void +setup_valid_nursery_objects (void) +{ + if (!valid_nursery_objects) + valid_nursery_objects = sgen_alloc_os_memory (DEFAULT_NURSERY_SIZE, SGEN_ALLOC_INTERNAL | SGEN_ALLOC_ACTIVATE, "debugging data"); + valid_nursery_object_count = 0; + sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, setup_mono_sgen_scan_area_with_callback, NULL, FALSE); +} + static gboolean find_object_in_nursery_dump (char *object) { @@ -250,31 +338,29 @@ find_object_in_nursery_dump (char *object) return FALSE; } -static void -describe_nursery_ptr (char *ptr) +static char* +describe_nursery_ptr (char *ptr, gboolean need_setup) { int i; - fprintf (gc_debug_file, "nursery-ptr "); + if (need_setup) + setup_valid_nursery_objects (); + for (i = 0; i < valid_nursery_object_count; ++i) { if (valid_nursery_objects [i] >= ptr) break; } if (i >= valid_nursery_object_count || valid_nursery_objects [i] + safe_object_get_size ((MonoObject *)valid_nursery_objects [i]) < ptr) { - fprintf (gc_debug_file, "(unalloc'd-memory)"); + SGEN_LOG (0, "nursery-ptr (unalloc'd-memory)\n"); + return NULL; } else { char *obj = valid_nursery_objects [i]; - MonoVTable *vtable = (MonoVTable*)LOAD_VTABLE (obj); - int size = safe_object_get_size ((MonoObject *)obj); - if (obj == ptr) - fprintf (gc_debug_file, "(object %s.%s size %d)", - vtable->klass->name_space, vtable->klass->name, size); + SGEN_LOG (0, "nursery-ptr\n"); else - fprintf (gc_debug_file, "(interior-ptr offset %td of %p (%s.%s) size %d)", - ptr - obj, obj, - vtable->klass->name_space, vtable->klass->name, size); + SGEN_LOG (0, "nursery-ptr (interior-ptr offset %td)\n", ptr - obj); + return obj; } } @@ -292,30 +378,16 @@ is_valid_object_pointer (char *object) return FALSE; } - -static void -describe_pointer (char *ptr) -{ - if (sgen_ptr_in_nursery (ptr)) { - describe_nursery_ptr (ptr); - } else if (major_collector.describe_pointer (ptr)) { - //Nothing really - } else if (!mono_sgen_los_describe_pointer (ptr)) { - fprintf (gc_debug_file, "non-heap-ptr"); - } -} - static void bad_pointer_spew (char *obj, char **slot) { char *ptr = *slot; MonoVTable *vtable = (MonoVTable*)LOAD_VTABLE (obj); - fprintf (gc_debug_file, "Invalid object pointer %p [", ptr); - describe_pointer (ptr); - fprintf (gc_debug_file, "] at offset %td in object %p (%s.%s).\n", + SGEN_LOG (0, "Invalid object pointer %p at offset %td in object %p (%s.%s):", ptr, (char*)slot - obj, obj, vtable->klass->name_space, vtable->klass->name); + describe_pointer (ptr, FALSE); broken_heap = TRUE; } @@ -325,7 +397,7 @@ missing_remset_spew (char *obj, char **slot) char *ptr = *slot; MonoVTable *vtable = (MonoVTable*)LOAD_VTABLE (obj); - fprintf (gc_debug_file, "Oldspace->newspace reference %p at offset %td in object %p (%s.%s) not found in remsets.\n", + SGEN_LOG (0, "Oldspace->newspace reference %p at offset %td in object %p (%s.%s) not found in remsets.", ptr, (char*)slot - obj, obj, vtable->klass->name_space, vtable->klass->name); @@ -341,16 +413,17 @@ FIXME Flag missing remsets due to pinning as non fatal if (!is_valid_object_pointer (*(char**)ptr)) { \ bad_pointer_spew ((char*)obj, (char**)ptr); \ } else if (!sgen_ptr_in_nursery (obj) && sgen_ptr_in_nursery ((char*)*ptr)) { \ - if (!sgen_get_remset ()->find_address ((char*)(ptr))) \ + if (!sgen_get_remset ()->find_address ((char*)(ptr)) && !sgen_cement_lookup ((char*)*(ptr)) && (!allow_missing_pinned || !SGEN_OBJECT_IS_PINNED ((char*)*(ptr)))) \ missing_remset_spew ((char*)obj, (char**)ptr); \ } \ } \ } while (0) static void -verify_object_pointers_callback (char *start, size_t size, void *dummy) +verify_object_pointers_callback (char *start, size_t size, void *data) { -#define SCAN_OBJECT_ACTION + gboolean allow_missing_pinned = (gboolean) (size_t) data; + #include "sgen-scan-object.h" } @@ -360,18 +433,14 @@ FIXME: depend on OP_DUMMY_USE. */ void -sgen_check_whole_heap (void) +sgen_check_whole_heap (gboolean allow_missing_pinned) { - /*setup valid_nursery_objects*/ - if (!valid_nursery_objects) - valid_nursery_objects = sgen_alloc_os_memory (DEFAULT_NURSERY_SIZE, SGEN_ALLOC_INTERNAL | SGEN_ALLOC_ACTIVATE, "debugging data"); - valid_nursery_object_count = 0; - sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, setup_mono_sgen_scan_area_with_callback, NULL, FALSE); + setup_valid_nursery_objects (); broken_heap = FALSE; - sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, verify_object_pointers_callback, NULL, FALSE); - major_collector.iterate_objects (TRUE, TRUE, verify_object_pointers_callback, NULL); - sgen_los_iterate_objects (verify_object_pointers_callback, NULL); + sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, verify_object_pointers_callback, (void*) (size_t) allow_missing_pinned, FALSE); + major_collector.iterate_objects (TRUE, TRUE, verify_object_pointers_callback, (void*) (size_t) allow_missing_pinned); + sgen_los_iterate_objects (verify_object_pointers_callback, (void*) (size_t) allow_missing_pinned); g_assert (!broken_heap); } @@ -400,4 +469,122 @@ sgen_check_objref (char *obj) g_assert (ptr_in_heap (obj)); } +static void +find_pinning_ref_from_thread (char *obj, size_t size) +{ + int j; + SgenThreadInfo *info; + char *endobj = obj + size; + + FOREACH_THREAD (info) { + char **start = (char**)info->stack_start; + if (info->skip) + continue; + while (start < (char**)info->stack_end) { + if (*start >= obj && *start < endobj) { + SGEN_LOG (0, "Object %p referenced in thread %p (id %p) at %p, stack: %p-%p", obj, info, (gpointer)mono_thread_info_get_tid (info), start, info->stack_start, info->stack_end); + } + start++; + } + + for (j = 0; j < ARCH_NUM_REGS; ++j) { +#ifdef USE_MONO_CTX + mword w = ((mword*)&info->ctx) [j]; +#else + mword w = (mword)&info->regs [j]; +#endif + + if (w >= (mword)obj && w < (mword)obj + size) + SGEN_LOG (0, "Object %p referenced in saved reg %d of thread %p (id %p)", obj, j, info, (gpointer)mono_thread_info_get_tid (info)); + } END_FOREACH_THREAD + } +} + +/* + * Debugging function: find in the conservative roots where @obj is being pinned. + */ +static G_GNUC_UNUSED void +find_pinning_reference (char *obj, size_t size) +{ + char **start; + RootRecord *root; + char *endobj = obj + size; + + SGEN_HASH_TABLE_FOREACH (&roots_hash [ROOT_TYPE_NORMAL], start, root) { + /* if desc is non-null it has precise info */ + if (!root->root_desc) { + while (start < (char**)root->end_root) { + if (*start >= obj && *start < endobj) { + SGEN_LOG (0, "Object %p referenced in pinned roots %p-%p\n", obj, start, root->end_root); + } + start++; + } + } + } SGEN_HASH_TABLE_FOREACH_END; + + find_pinning_ref_from_thread (obj, size); +} + +#undef HANDLE_PTR +#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)); \ + } else { \ + g_assert_not_reached (); \ + } \ + } \ + } while (0) + +static void +check_marked_callback (char *start, size_t size, void *dummy) +{ + gboolean is_los = (gboolean) (size_t) dummy; + + if (is_los) { + if (!sgen_los_object_is_pinned (start)) + return; + } else { + if (!major_collector.is_object_live (start)) + return; + } + +#include "sgen-scan-object.h" +} + +void +sgen_check_major_heap_marked (void) +{ + setup_valid_nursery_objects (); + + major_collector.iterate_objects (TRUE, TRUE, check_marked_callback, (void*)FALSE); + sgen_los_iterate_objects (check_marked_callback, (void*)TRUE); +} + +static void +check_nursery_objects_pinned_callback (char *obj, size_t size, void *data /* ScanCopyContext *ctx */) +{ + gboolean pinned = (gboolean) (size_t) data; + + g_assert (!SGEN_OBJECT_IS_FORWARDED (obj)); + if (pinned) + g_assert (SGEN_OBJECT_IS_PINNED (obj)); + else + g_assert (!SGEN_OBJECT_IS_PINNED (obj)); +} + +void +sgen_check_nursery_objects_pinned (gboolean pinned) +{ + sgen_clear_nursery_fragments (); + sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, + (IterateObjectCallbackFunc)check_nursery_objects_pinned_callback, (void*) (size_t) pinned /* (void*)&ctx */, FALSE); +} + #endif /*HAVE_SGEN_GC*/