+2010-04-27 Mark Probst <mark.probst@gmail.com>
+
+ * sgen-gc.c, sgen-marksweep.c, sgen-major-copying.c: Don't do a
+ separate pass to scan pinned and large object but use the gray
+ queue like for regular objects.
+
2010-04-26 Zoltan Varga <vargaz@gmail.com>
* boehm-gc.c: Applied patch from Robert Nagy (robert@openbsd.org). Include
struct _LOSObject {
LOSObject *next;
mword size; /* this is the object size */
- int dummy; /* to have a sizeof (LOSObject) a multiple of ALLOC_ALIGN and data starting at same alignment */
guint16 role;
- guint16 scanned;
+ int dummy; /* to have a sizeof (LOSObject) a multiple of ALLOC_ALIGN and data starting at same alignment */
char data [MONO_ZERO_LEN_ARRAY];
};
static void scan_from_remsets (void *start_nursery, void *end_nursery);
static void scan_from_registered_roots (CopyOrMarkObjectFunc copy_func, char *addr_start, char *addr_end, int root_type);
static void scan_finalizer_entries (CopyOrMarkObjectFunc copy_func, FinalizeEntry *list);
-static int scan_needed_big_objects (ScanObjectFunc scan_func);
static void find_pinning_ref_from_thread (char *obj, size_t size);
static void update_current_thread_stack (void *start);
static void finalize_in_range (CopyOrMarkObjectFunc copy_func, char *start, char *end, int generation);
static char* major_scan_object (char *start);
static void* copy_object_no_checks (void *obj);
static void copy_object (void **obj_slot);
-static void scan_from_pinned_objects (void);
-static void scan_pinned_objects_in_section (GCMemSection *section, ScanObjectFunc scan_func);
-static void scan_pinned_objects_in_nursery (ScanObjectFunc scan_func);
static void* get_chunk_freelist (PinnedChunk *chunk, int slot);
static PinnedChunk* alloc_pinned_chunk (void);
static void free_large_object (LOSObject *obj);
static void sort_addresses (void **array, int size);
+static void drain_gray_stack (void);
static void finish_gray_stack (char *start_addr, char *end_addr, int generation);
static void mono_gc_register_disappearing_link (MonoObject *obj, void **link, gboolean track);
return start;
}
-static void
-scan_pinned_objects_in_section (GCMemSection *section, ScanObjectFunc scan_func)
-{
- int i;
- for (i = section->pin_queue_start; i < section->pin_queue_end; ++i) {
- DEBUG (6, fprintf (gc_debug_file, "Precise object scan %d of pinned %p (%s)\n",
- i, pin_queue [i], safe_name (pin_queue [i])));
- scan_func (pin_queue [i]);
- }
-}
-
-static void
-scan_pinned_objects_in_nursery (ScanObjectFunc scan_func)
-{
- scan_pinned_objects_in_section (nursery_section, scan_func);
-}
-
/*
* drain_gray_stack:
*
DEBUG (4, fprintf (gc_debug_file, "Pinned object %p, vtable %p (%s), count %d\n", search_start, *(void**)search_start, safe_name (search_start), count));
binary_protocol_pin (search_start, (gpointer)LOAD_VTABLE (search_start), safe_object_get_size (search_start));
pin_object (search_start);
+ GRAY_OBJECT_ENQUEUE (search_start);
if (heap_dump_file)
pin_stats_register_object (search_start, last_obj_size);
definitely_pinned [count] = search_start;
}
}
-static int
-scan_needed_big_objects (ScanObjectFunc scan_func)
-{
- LOSObject *big_object;
- int count = 0;
- for (big_object = los_object_list; big_object; big_object = big_object->next) {
- if (!big_object->scanned && object_is_pinned (big_object->data)) {
- DEBUG (5, fprintf (gc_debug_file, "Scan of big object: %p (%s), size: %zd\n", big_object->data, safe_name (big_object->data), big_object->size));
- scan_func (big_object->data);
- drain_gray_stack ();
- big_object->scanned = TRUE;
- count++;
- }
- }
- return count;
-}
-
static const char*
generation_name (int generation)
{
{
TV_DECLARE (atv);
TV_DECLARE (btv);
- int fin_ready, bigo_scanned_num;
+ int fin_ready;
CopyOrMarkObjectFunc copy_func = current_collection_generation == GENERATION_NURSERY ? copy_object : major_copy_or_mark_object;
- ScanObjectFunc scan_func = current_collection_generation == GENERATION_NURSERY ? scan_object : major_scan_object;
/*
* We copied all the reachable objects. Now it's the time to copy
finalize_in_range (copy_func, start_addr, end_addr, generation);
if (generation == GENERATION_OLD)
finalize_in_range (copy_func, nursery_start, nursery_real_end, GENERATION_NURSERY);
- bigo_scanned_num = scan_needed_big_objects (scan_func);
/* drain the new stack that might have been created */
DEBUG (6, fprintf (gc_debug_file, "Precise scan of gray area post fin\n"));
drain_gray_stack ();
- } while (fin_ready != num_ready_finalizers || bigo_scanned_num);
+ } while (fin_ready != num_ready_finalizers);
TV_GETTIME (btv);
DEBUG (2, fprintf (gc_debug_file, "Finalize queue handling scan for %s generation: %d usecs\n", generation_name (generation), TV_ELAPSED (atv, btv)));
time_minor_scan_remsets += TV_ELAPSED_MS (atv, btv);
DEBUG (2, fprintf (gc_debug_file, "Old generation scan: %d usecs\n", TV_ELAPSED (atv, btv)));
- /* the pinned objects are roots */
- scan_pinned_objects_in_nursery (scan_object);
+ drain_gray_stack ();
+
TV_GETTIME (atv);
time_minor_scan_pinned += TV_ELAPSED_MS (btv, atv);
/* registered roots, this includes static fields */
alloc_size &= ~(pagesize - 1);
/* FIXME: handle OOM */
obj = get_os_memory (alloc_size, TRUE);
+ g_assert (!((mword)obj->data & (ALLOC_ALIGN - 1)));
obj->size = size;
vtslot = (void**)obj->data;
*vtslot = vtable;
objsize &= ~(ALLOC_ALIGN - 1);
if (G_UNLIKELY (objsize > MAX_SMALL_OBJ_SIZE || obj_is_from_pinned_alloc (obj))) {
+ if (object_is_pinned (obj))
+ return;
DEBUG (9, fprintf (gc_debug_file, " (marked LOS/Pinned %p (%s), size: %zd)\n", obj, safe_name (obj), objsize));
binary_protocol_pin (obj, (gpointer)LOAD_VTABLE (obj), safe_object_get_size ((MonoObject*)obj));
pin_object (obj);
+ GRAY_OBJECT_ENQUEUE (obj);
HEAVY_STAT (++stat_copy_object_failed_large_pinned);
return;
}
if (heap_dump_file && !object_is_pinned (addr))
pin_stats_register_object ((char*) addr, safe_object_get_size ((MonoObject*) addr));
pin_object (addr);
+ GRAY_OBJECT_ENQUEUE (addr);
DEBUG (6, fprintf (gc_debug_file, "Marked pinned object %p (%s) from roots\n", addr, safe_name (addr)));
}
}
scan_pinned_objects (sweep_pinned_objects_callback, NULL);
}
-static void
-scan_object_callback (char *ptr, size_t size, void *data)
-{
- DEBUG (6, fprintf (gc_debug_file, "Precise object scan of alloc_pinned %p (%s)\n", ptr, safe_name (ptr)));
- /* FIXME: Put objects without references into separate chunks
- which do not need to be scanned */
- major_scan_object (ptr);
-}
-
-static void
-scan_from_pinned_objects (void)
-{
- scan_pinned_objects ((IterateObjectCallbackFunc)scan_object_callback, NULL);
-}
-
static void
major_iterate_objects (gboolean non_pinned, gboolean pinned, IterateObjectCallbackFunc callback, void *data)
{
init_stats ();
binary_protocol_collection (GENERATION_OLD);
check_scan_starts ();
+ gray_object_queue_init ();
degraded_mode = 0;
DEBUG (1, fprintf (gc_debug_file, "Start major collection %d\n", num_major_gcs));
find_optimized_pin_queue_area (bigobj->data, (char*)bigobj->data + bigobj->size, &start, &end);
if (start != end) {
pin_object (bigobj->data);
+ GRAY_OBJECT_ENQUEUE (bigobj->data);
if (heap_dump_file)
pin_stats_register_object ((char*) bigobj->data, safe_object_get_size ((MonoObject*) bigobj->data));
DEBUG (6, fprintf (gc_debug_file, "Marked large object %p (%s) size: %zd from roots\n", bigobj->data, safe_name (bigobj->data), bigobj->size));
DEBUG (4, fprintf (gc_debug_file, "Start scan with %d pinned objects\n", next_pin_slot));
new_to_space_section ();
- gray_object_queue_init ();
- /* the old generation doesn't need to be scanned (no remembered sets or card
- * table needed either): the only objects that must survive are those pinned and
- * those referenced by the precise roots.
- * mark any section without pinned objects, so we can free it since we will be able to
- * move all the objects.
- */
- /* the pinned objects are roots (big objects are included in this list, too) */
- scan_pinned_objects_in_nursery (major_scan_object);
- for (section = section_list; section; section = section->block.next)
- scan_pinned_objects_in_section (section, major_scan_object);
- for (bigobj = los_object_list; bigobj; bigobj = bigobj->next) {
- if (object_is_pinned (bigobj->data)) {
- DEBUG (6, fprintf (gc_debug_file, "Precise object scan pinned LOS object %p (%s)\n",
- bigobj->data, safe_name (bigobj->data)));
- major_scan_object (bigobj->data);
- }
- }
+ drain_gray_stack ();
+
TV_GETTIME (atv);
time_major_scan_pinned += TV_ELAPSED_MS (btv, atv);
TV_GETTIME (atv);
time_major_scan_thread_data += TV_ELAPSED_MS (btv, atv);
- /* alloc_pinned objects */
- /*
- * FIXME: This should not be necessary - reachable pinned
- * objects should have been put in the gray queue and
- * non-reachable ones shouldn't be scanned.
- */
- scan_from_pinned_objects ();
TV_GETTIME (btv);
time_major_scan_alloc_pinned += TV_ELAPSED_MS (atv, btv);
time_major_scan_finalized += TV_ELAPSED_MS (btv, atv);
DEBUG (2, fprintf (gc_debug_file, "Root scan: %d usecs\n", TV_ELAPSED (btv, atv)));
- /* we need to go over the big object list to see if any was marked and scan it
- * And we need to make this in a loop, considering that objects referenced by finalizable
- * objects could reference big objects (this happens in finish_gray_stack ())
- */
- scan_needed_big_objects (major_scan_object);
TV_GETTIME (btv);
time_major_scan_big_objects += TV_ELAPSED_MS (atv, btv);
for (bigobj = los_object_list; bigobj;) {
if (object_is_pinned (bigobj->data)) {
unpin_object (bigobj->data);
- bigobj->scanned = FALSE;
} else {
LOSObject *to_free;
/* not referenced anywhere, so we can free it */
objsize &= ~(ALLOC_ALIGN - 1);
if (objsize > MAX_SMALL_OBJ_SIZE) {
+ if (object_is_pinned (obj))
+ return;
binary_protocol_pin (obj, (gpointer)LOAD_VTABLE (obj), safe_object_get_size ((MonoObject*)obj));
pin_object (obj);
+ GRAY_OBJECT_ENQUEUE (obj);
return;
}
MS_MARK_INDEX_IN_BLOCK_AND_ENQUEUE (obj, block, index);
}
-static void
-scan_object_callback (char *ptr, size_t size, void *data)
-{
- major_scan_object (ptr);
-}
-
-/*
- * FIXME: This is essentially the same as the corresponding function
- * in sgen-major-copying.c. Unify (or eliminate - see comment in
- * major_do_collection())!
- */
-static void
-scan_from_pinned_objects (void)
-{
- major_iterate_objects (FALSE, TRUE, scan_object_callback, NULL);
-}
-
static void
mark_pinned_objects_in_block (MSBlockInfo *block)
{
int start, end;
find_optimized_pin_queue_area (bigobj->data, (char*)bigobj->data + bigobj->size, &start, &end);
if (start != end) {
- /* FIXME: just put them in the gray queue,
- then we don't have to do the second loop
- below */
pin_object (bigobj->data);
+ GRAY_OBJECT_ENQUEUE (bigobj->data);
if (heap_dump_file)
pin_stats_register_object ((char*) bigobj->data, safe_object_get_size ((MonoObject*) bigobj->data));
DEBUG (6, fprintf (gc_debug_file, "Marked large object %p (%s) size: %zd from roots\n", bigobj->data, safe_name (bigobj->data), bigobj->size));
DEBUG (2, fprintf (gc_debug_file, "Finding pinned pointers: %d in %d usecs\n", next_pin_slot, TV_ELAPSED (atv, btv)));
DEBUG (4, fprintf (gc_debug_file, "Start scan with %d pinned objects\n", next_pin_slot));
- /* the old generation doesn't need to be scanned (no remembered sets or card
- * table needed either): the only objects that must survive are those pinned and
- * those referenced by the precise roots.
- * mark any section without pinned objects, so we can free it since we will be able to
- * move all the objects.
- */
- /* the pinned objects are roots (big objects are included in this list, too) */
- scan_pinned_objects_in_nursery (major_scan_object);
- for (bigobj = los_object_list; bigobj; bigobj = bigobj->next) {
- if (object_is_pinned (bigobj->data)) {
- DEBUG (6, fprintf (gc_debug_file, "Precise object scan pinned LOS object %p (%s)\n",
- bigobj->data, safe_name (bigobj->data)));
- major_scan_object (bigobj->data);
- }
- }
+ drain_gray_stack ();
+
TV_GETTIME (atv);
time_major_scan_pinned += TV_ELAPSED_MS (btv, atv);
TV_GETTIME (atv);
time_major_scan_thread_data += TV_ELAPSED_MS (btv, atv);
- /* alloc_pinned objects */
- /*
- * FIXME: This should not be necessary - reachable pinned
- * objects should have been put in the gray queue and
- * non-reachable ones shouldn't be scanned.
- */
- scan_from_pinned_objects ();
TV_GETTIME (btv);
time_major_scan_alloc_pinned += TV_ELAPSED_MS (atv, btv);
time_major_scan_finalized += TV_ELAPSED_MS (btv, atv);
DEBUG (2, fprintf (gc_debug_file, "Root scan: %d usecs\n", TV_ELAPSED (btv, atv)));
- /* we need to go over the big object list to see if any was marked and scan it
- * And we need to make this in a loop, considering that objects referenced by finalizable
- * objects could reference big objects (this happens in finish_gray_stack ())
- */
- scan_needed_big_objects (major_scan_object);
TV_GETTIME (btv);
time_major_scan_big_objects += TV_ELAPSED_MS (atv, btv);
for (bigobj = los_object_list; bigobj;) {
if (object_is_pinned (bigobj->data)) {
unpin_object (bigobj->data);
- bigobj->scanned = FALSE;
} else {
LOSObject *to_free;
/* not referenced anywhere, so we can free it */