static void describe_nursery_ptr (char *ptr) { int i; fprintf (gc_debug_file, "nursery-ptr "); 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)"); } 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); 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); } }
/* * Check that each object reference which points into the nursery can * be found in the remembered sets. */ 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)); #define SCAN_OBJECT_ACTION #include "sgen-scan-object.h" }
static void count_pinned_callback (char *obj, size_t size, void *data) { MonoVTable *vtable = (MonoVTable*)LOAD_VTABLE (obj); if (vtable->klass->has_references) ++count_pinned_ref; else ++count_pinned_nonref; }
void describe_ptr (char *ptr) { MonoVTable *vtable; mword desc; int type; char *start; if (sgen_ptr_in_nursery (ptr)) { printf ("Pointer inside nursery.\n"); } else { if (sgen_ptr_is_in_los (ptr, &start)) { if (ptr == start) printf ("Pointer is the start of object %p in LOS space.\n", start); 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"); } else if (major_collector.obj_is_from_pinned_alloc (ptr)) { printf ("Pointer is inside a pinned chunk.\n"); } else { printf ("Pointer unknown.\n"); return; } } 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); printf ("VTable: %p\n", vtable); if (vtable == NULL) { printf ("VTable is invalid (empty).\n"); return; } if (sgen_ptr_in_nursery (vtable)) { printf ("VTable is invalid (points inside nursery).\n"); return; } printf ("Class: %s\n", vtable->klass->name); desc = ((GCVTable*)vtable)->desc; printf ("Descriptor: %lx\n", (long)desc); type = desc & 0x7; printf ("Descriptor type: %d (%s)\n", type, descriptor_types [type]); }
static void 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", ptr, (char*)slot - obj, obj, vtable->klass->name_space, vtable->klass->name); broken_heap = TRUE; }
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", (char*)slot - obj, obj, vtable->klass->name_space, vtable->klass->name); broken_heap = TRUE; }
static void mono_sgen_ssb_record_pointer (gpointer ptr) { RememberedSet *rs; gboolean lock = mono_sgen_collection_is_parallel (); gpointer obj = *(gpointer*)ptr; g_assert (!mono_sgen_ptr_in_nursery (ptr) && mono_sgen_ptr_in_nursery (obj)); if (lock) LOCK_GLOBAL_REMSET; if (!global_remset_location_was_not_added (ptr)) goto done; if (G_UNLIKELY (do_pin_stats)) mono_sgen_pin_stats_register_global_remset (obj); DEBUG (8, fprintf (gc_debug_file, "Adding global remset for %p\n", ptr)); binary_protocol_global_remset (ptr, *(gpointer*)ptr, (gpointer)LOAD_VTABLE (obj)); HEAVY_STAT (++stat_global_remsets_added); /* * FIXME: If an object remains pinned, we need to add it at every minor collection. * To avoid uncontrolled growth of the global remset, only add each pointer once. */ if (global_remset->store_next + 3 < global_remset->end_set) { *(global_remset->store_next++) = (mword)ptr; goto done; } rs = mono_sgen_alloc_remset (global_remset->end_set - global_remset->data, NULL, TRUE); rs->next = global_remset; global_remset = rs; *(global_remset->store_next++) = (mword)ptr; { int global_rs_size = 0; for (rs = global_remset; rs; rs = rs->next) { global_rs_size += rs->store_next - rs->data; } DEBUG (4, fprintf (gc_debug_file, "Global remset now has size %d\n", global_rs_size)); } done: if (lock) UNLOCK_GLOBAL_REMSET; }
static mword* handle_remset (mword *p, void *start_nursery, void *end_nursery, gboolean global, SgenGrayQueue *queue) { void **ptr; mword count; mword desc; if (global) HEAVY_STAT (++stat_global_remsets_processed); else HEAVY_STAT (++stat_local_remsets_processed); /* FIXME: exclude stack locations */ switch ((*p) & REMSET_TYPE_MASK) { case REMSET_LOCATION: ptr = (void**)(*p); //__builtin_prefetch (ptr); if (((void*)ptr < start_nursery || (void*)ptr >= end_nursery)) { gpointer old = *ptr; major_collector.copy_object (ptr, queue); DEBUG (9, fprintf (gc_debug_file, "Overwrote remset at %p with %p\n", ptr, *ptr)); if (old) binary_protocol_ptr_update (ptr, old, *ptr, (gpointer)LOAD_VTABLE (*ptr), mono_sgen_safe_object_get_size (*ptr)); if (!global && *ptr >= start_nursery && *ptr < end_nursery) { /* * If the object is pinned, each reference to it from nonpinned objects * becomes part of the global remset, which can grow very large. */ DEBUG (9, fprintf (gc_debug_file, "Add to global remset because of pinning %p (%p %s)\n", ptr, *ptr, mono_sgen_safe_name (*ptr))); mono_sgen_add_to_global_remset (ptr); } } else { DEBUG (9, fprintf (gc_debug_file, "Skipping remset at %p holding %p\n", ptr, *ptr)); } return p + 1; case REMSET_RANGE: ptr = (void**)(*p & ~REMSET_TYPE_MASK); if (((void*)ptr >= start_nursery && (void*)ptr < end_nursery)) return p + 2; count = p [1]; while (count-- > 0) { major_collector.copy_object (ptr, queue); DEBUG (9, fprintf (gc_debug_file, "Overwrote remset at %p with %p (count: %d)\n", ptr, *ptr, (int)count)); if (!global && *ptr >= start_nursery && *ptr < end_nursery) mono_sgen_add_to_global_remset (ptr); ++ptr; } return p + 2; case REMSET_OBJECT: ptr = (void**)(*p & ~REMSET_TYPE_MASK); if (((void*)ptr >= start_nursery && (void*)ptr < end_nursery)) return p + 1; mono_sgen_get_minor_scan_object () ((char*)ptr, queue); return p + 1; case REMSET_VTYPE: { ScanVTypeFunc scan_vtype = mono_sgen_get_minor_scan_vtype (); size_t skip_size; ptr = (void**)(*p & ~REMSET_TYPE_MASK); if (((void*)ptr >= start_nursery && (void*)ptr < end_nursery)) return p + 4; desc = p [1]; count = p [2]; skip_size = p [3]; while (count-- > 0) { scan_vtype ((char*)ptr, desc, queue); ptr = (void**)((char*)ptr + skip_size); } return p + 4; } default: g_assert_not_reached (); } return NULL; }
static void major_sweep (void) { int i; #ifdef FIXED_HEAP int j; #else MSBlockInfo **iter; #endif /* clear all the free lists */ for (i = 0; i < MS_BLOCK_TYPE_MAX; ++i) { MSBlockInfo **free_blocks = free_block_lists [i]; int j; for (j = 0; j < num_block_obj_sizes; ++j) free_blocks [j] = NULL; } /* traverse all blocks, free and zero unmarked objects */ #ifdef FIXED_HEAP for (j = 0; j < ms_heap_num_blocks; ++j) { MSBlockInfo *block = &block_infos [j]; #else iter = &all_blocks; while (*iter) { MSBlockInfo *block = *iter; #endif int count; gboolean have_live = FALSE; int obj_index; #ifdef FIXED_HEAP if (!block->used) continue; #endif count = MS_BLOCK_FREE / block->obj_size; block->free_list = NULL; for (obj_index = 0; obj_index < count; ++obj_index) { int word, bit; void *obj = MS_BLOCK_OBJ (block, obj_index); MS_CALC_MARK_BIT (word, bit, obj); if (MS_MARK_BIT (block, word, bit)) { DEBUG (9, g_assert (MS_OBJ_ALLOCED (obj, block))); have_live = TRUE; } else { /* an unmarked object */ if (MS_OBJ_ALLOCED (obj, block)) { binary_protocol_empty (obj, block->obj_size); memset (obj, 0, block->obj_size); } *(void**)obj = block->free_list; block->free_list = obj; } } /* reset mark bits */ memset (block->mark_words, 0, sizeof (mword) * MS_NUM_MARK_WORDS); /* * FIXME: reverse free list so that it's in address * order */ if (have_live) { #ifndef FIXED_HEAP iter = &block->next; #endif /* * If there are free slots in the block, add * the block to the corresponding free list. */ if (block->free_list) { MSBlockInfo **free_blocks = FREE_BLOCKS (block->pinned, block->has_references); int index = MS_BLOCK_OBJ_SIZE_INDEX (block->obj_size); block->next_free = free_blocks [index]; free_blocks [index] = block; } } else { /* * Blocks without live objects are removed from the * block list and freed. */ #ifdef FIXED_HEAP ms_free_block (block); #else *iter = block->next; ms_free_block (block->block); mono_sgen_free_internal (block, INTERNAL_MEM_MS_BLOCK_INFO); #endif --num_major_sections; } } } static int count_pinned_ref; static int count_pinned_nonref; static int count_nonpinned_ref; static int count_nonpinned_nonref; static void count_nonpinned_callback (char *obj, size_t size, void *data) { MonoVTable *vtable = (MonoVTable*)LOAD_VTABLE (obj); if (vtable->klass->has_references) ++count_nonpinned_ref; else ++count_nonpinned_nonref; }