X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fsgen-bridge.c;h=86478b00b8cf1f86e85574ae7a57120db4256265;hb=9f92e1c7fd7b2553fb4567b51426209506797af8;hp=e675f91dd1e26a2e4565da8143dda6eca7dcde3b;hpb=d8f724157b5a065d12ec4f8657e87006a0f8bde8;p=mono.git diff --git a/mono/metadata/sgen-bridge.c b/mono/metadata/sgen-bridge.c index e675f91dd1e..86478b00b8c 100644 --- a/mono/metadata/sgen-bridge.c +++ b/mono/metadata/sgen-bridge.c @@ -51,344 +51,12 @@ #include "utils/mono-time.h" #include "utils/mono-compiler.h" - -typedef struct { - int size; - int capacity; - char *data; -} DynArray; - -/*Specializations*/ - -typedef struct { - DynArray array; -} DynIntArray; - -typedef struct { - DynArray array; -} DynPtrArray; - -typedef struct { - DynArray array; -} DynSCCArray; - - -/* - * FIXME: Optimizations: - * - * Don't allocate a scrs array for just one source. Most objects have - * just one source, so use the srcs pointer itself. - */ -typedef struct _HashEntry { - MonoObject *obj; /* This is a duplicate - it's already stored in the hash table */ - - gboolean is_bridge; - gboolean is_visited; - - int finishing_time; - - DynPtrArray srcs; - - int scc_index; -} HashEntry; - -typedef struct _SCC { - int index; - int api_index; - int num_bridge_entries; - DynIntArray xrefs; /* these are incoming, not outgoing */ -} SCC; - -static SgenHashTable hash_table = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_HASH_TABLE, INTERNAL_MEM_BRIDGE_HASH_TABLE_ENTRY, sizeof (HashEntry), mono_aligned_addr_hash, NULL); - -static MonoGCBridgeCallbacks bridge_callbacks; - -static int current_time; +MonoGCBridgeCallbacks bridge_callbacks; +static SgenBridgeProcessor bridge_processor; +static SgenBridgeProcessor compare_to_bridge_processor; gboolean bridge_processing_in_progress = FALSE; - - -/* Core functions */ -/* public */ - -/* private */ - -static void -dyn_array_init (DynArray *da) -{ - da->size = 0; - da->capacity = 0; - da->data = NULL; -} - -static void -dyn_array_uninit (DynArray *da, int elem_size) -{ - if (da->capacity <= 0) - return; - - sgen_free_internal_dynamic (da->data, elem_size * da->capacity, INTERNAL_MEM_BRIDGE_DATA); - da->data = NULL; -} - -static void -dyn_array_ensure_capacity (DynArray *da, int capacity, int elem_size) -{ - int old_capacity = da->capacity; - char *new_data; - - if (capacity <= old_capacity) - return; - - if (da->capacity == 0) - da->capacity = 2; - while (capacity > da->capacity) - da->capacity *= 2; - - new_data = sgen_alloc_internal_dynamic (elem_size * da->capacity, INTERNAL_MEM_BRIDGE_DATA, TRUE); - memcpy (new_data, da->data, elem_size * da->size); - sgen_free_internal_dynamic (da->data, elem_size * old_capacity, INTERNAL_MEM_BRIDGE_DATA); - da->data = new_data; -} - -static void* -dyn_array_add (DynArray *da, int elem_size) -{ - void *p; - - dyn_array_ensure_capacity (da, da->size + 1, elem_size); - - p = da->data + da->size * elem_size; - ++da->size; - return p; -} - -/* int */ -static void -dyn_array_int_init (DynIntArray *da) -{ - dyn_array_init (&da->array); -} - -static void -dyn_array_int_uninit (DynIntArray *da) -{ - dyn_array_uninit (&da->array, sizeof (int)); -} - -static int -dyn_array_int_size (DynIntArray *da) -{ - return da->array.size; -} - -static void -dyn_array_int_set_size (DynIntArray *da, int size) -{ - da->array.size = size; -} - -static void -dyn_array_int_add (DynIntArray *da, int x) -{ - int *p = dyn_array_add (&da->array, sizeof (int)); - *p = x; -} - -static int -dyn_array_int_get (DynIntArray *da, int x) -{ - return ((int*)da->array.data)[x]; -} - -static void -dyn_array_int_set (DynIntArray *da, int idx, int val) -{ - ((int*)da->array.data)[idx] = val; -} - -static void -dyn_array_int_ensure_capacity (DynIntArray *da, int capacity) -{ - dyn_array_ensure_capacity (&da->array, capacity, sizeof (int)); -} - -static void -dyn_array_int_set_all (DynIntArray *dst, DynIntArray *src) -{ - dyn_array_int_ensure_capacity (dst, src->array.size); - memcpy (dst->array.data, src->array.data, src->array.size * sizeof (int)); - dst->array.size = src->array.size; -} - -/* ptr */ - -static void -dyn_array_ptr_init (DynPtrArray *da) -{ - dyn_array_init (&da->array); -} - -static void -dyn_array_ptr_uninit (DynPtrArray *da) -{ - dyn_array_uninit (&da->array, sizeof (void*)); -} - -static int -dyn_array_ptr_size (DynPtrArray *da) -{ - return da->array.size; -} - -static void -dyn_array_ptr_set_size (DynPtrArray *da, int size) -{ - da->array.size = size; -} - -static void* -dyn_array_ptr_get (DynPtrArray *da, int x) -{ - return ((void**)da->array.data)[x]; -} - -static void -dyn_array_ptr_add (DynPtrArray *da, void *ptr) -{ - void **p = dyn_array_add (&da->array, sizeof (void*)); - *p = ptr; -} - -#define dyn_array_ptr_push dyn_array_ptr_add - -static void* -dyn_array_ptr_pop (DynPtrArray *da) -{ - void *p; - int size = da->array.size; - g_assert (size > 0); - p = dyn_array_ptr_get (da, size - 1); - --da->array.size; - return p; -} - -/*SCC */ - -static void -dyn_array_scc_init (DynSCCArray *da) -{ - dyn_array_init (&da->array); -} - -static void -dyn_array_scc_uninit (DynSCCArray *da) -{ - dyn_array_uninit (&da->array, sizeof (SCC)); -} - -static int -dyn_array_scc_size (DynSCCArray *da) -{ - return da->array.size; -} - -static SCC* -dyn_array_scc_add (DynSCCArray *da) -{ - return dyn_array_add (&da->array, sizeof (SCC)); -} - -static SCC* -dyn_array_scc_get_ptr (DynSCCArray *da, int x) -{ - return &((SCC*)da->array.data)[x]; -} - -/* Merge code*/ - -static DynIntArray merge_array; - -static gboolean -dyn_array_int_contains (DynIntArray *da, int x) -{ - int i; - for (i = 0; i < dyn_array_int_size (da); ++i) - if (dyn_array_int_get (da, i) == x) - return TRUE; - return FALSE; -} - - -static void -dyn_array_int_merge (DynIntArray *dst, DynIntArray *src) -{ - int i, j; - - dyn_array_int_ensure_capacity (&merge_array, dyn_array_int_size (dst) + dyn_array_int_size (src)); - dyn_array_int_set_size (&merge_array, 0); - - for (i = j = 0; i < dyn_array_int_size (dst) || j < dyn_array_int_size (src); ) { - if (i < dyn_array_int_size (dst) && j < dyn_array_int_size (src)) { - int a = dyn_array_int_get (dst, i); - int b = dyn_array_int_get (src, j); - if (a < b) { - dyn_array_int_add (&merge_array, a); - ++i; - } else if (a == b) { - dyn_array_int_add (&merge_array, a); - ++i; - ++j; - } else { - dyn_array_int_add (&merge_array, b); - ++j; - } - } else if (i < dyn_array_int_size (dst)) { - dyn_array_int_add (&merge_array, dyn_array_int_get (dst, i)); - ++i; - } else { - dyn_array_int_add (&merge_array, dyn_array_int_get (src, j)); - ++j; - } - } - - if (dyn_array_int_size (&merge_array) > dyn_array_int_size (dst)) { - dyn_array_int_set_all (dst, &merge_array); - } -} - -static void -dyn_array_int_merge_one (DynIntArray *array, int value) -{ - int i; - int tmp; - int size = dyn_array_int_size (array); - - for (i = 0; i < size; ++i) { - if (dyn_array_int_get (array, i) == value) - return; - else if (dyn_array_int_get (array, i) > value) - break; - } - - dyn_array_int_ensure_capacity (array, size + 1); - - if (i < size) { - tmp = dyn_array_int_get (array, i); - for (; i < size; ++i) { - dyn_array_int_set (array, i, value); - value = tmp; - tmp = dyn_array_int_get (array, i + 1); - } - dyn_array_int_set (array, size, value); - } else { - dyn_array_int_set (array, size, value); - } - - dyn_array_int_set_size (array, size + 1); -} - void mono_gc_wait_for_bridge_processing (void) { @@ -401,6 +69,7 @@ mono_gc_wait_for_bridge_processing (void) sgen_gc_unlock (); } + void mono_gc_register_bridge_callbacks (MonoGCBridgeCallbacks *callbacks) { @@ -408,297 +77,77 @@ mono_gc_register_bridge_callbacks (MonoGCBridgeCallbacks *callbacks) g_error ("Invalid bridge callback version. Expected %d but got %d\n", SGEN_BRIDGE_VERSION, callbacks->bridge_version); bridge_callbacks = *callbacks; -} - -gboolean -sgen_is_bridge_object (MonoObject *obj) -{ - if ((obj->vtable->gc_bits & SGEN_GC_BIT_BRIDGE_OBJECT) != SGEN_GC_BIT_BRIDGE_OBJECT) - return FALSE; - return bridge_callbacks.is_bridge_object (obj); -} - -MonoGCBridgeObjectKind -sgen_bridge_class_kind (MonoClass *class) -{ - return bridge_callbacks.bridge_class_kind (class); -} - -gboolean -sgen_need_bridge_processing (void) -{ - return bridge_callbacks.cross_references != NULL; -} - -static HashEntry* -get_hash_entry (MonoObject *obj, gboolean *existing) -{ - HashEntry *entry = sgen_hash_table_lookup (&hash_table, obj); - HashEntry new_entry; - - if (entry) { - if (existing) - *existing = TRUE; - return entry; - } - if (existing) - *existing = FALSE; - - memset (&new_entry, 0, sizeof (HashEntry)); - - new_entry.obj = obj; - dyn_array_ptr_init (&new_entry.srcs); - new_entry.finishing_time = -1; - new_entry.scc_index = -1; - - sgen_hash_table_replace (&hash_table, obj, &new_entry, NULL); - return sgen_hash_table_lookup (&hash_table, obj); -} - -static void -add_source (HashEntry *entry, HashEntry *src) -{ - dyn_array_ptr_add (&entry->srcs, src); -} - -static void -free_data (void) -{ - MonoObject *obj; - HashEntry *entry; - int total_srcs = 0; - int max_srcs = 0; - - SGEN_HASH_TABLE_FOREACH (&hash_table, obj, entry) { - int entry_size = dyn_array_ptr_size (&entry->srcs); - total_srcs += entry_size; - if (entry_size > max_srcs) - max_srcs = entry_size; - dyn_array_ptr_uninit (&entry->srcs); - } SGEN_HASH_TABLE_FOREACH_END; - - sgen_hash_table_clean (&hash_table); - - dyn_array_int_uninit (&merge_array); - //g_print ("total srcs %d - max %d\n", total_srcs, max_srcs); -} - -static HashEntry* -register_bridge_object (MonoObject *obj) -{ - HashEntry *entry = get_hash_entry (obj, NULL); - entry->is_bridge = TRUE; - return entry; -} - -static void -register_finishing_time (HashEntry *entry, int t) -{ - g_assert (entry->finishing_time < 0); - entry->finishing_time = t; + if (!bridge_processor.reset_data) + sgen_old_bridge_init (&bridge_processor); } static gboolean -object_is_live (MonoObject **objp) -{ - MonoObject *obj = *objp; - MonoObject *fwd = SGEN_OBJECT_IS_FORWARDED (obj); - if (fwd) { - *objp = fwd; - return sgen_hash_table_lookup (&hash_table, fwd) == NULL; - } - if (!sgen_object_is_live (obj)) - return FALSE; - return sgen_hash_table_lookup (&hash_table, obj) == NULL; -} - -static DynPtrArray registered_bridges; -static DynPtrArray dfs_stack; - -static int dsf1_passes, dsf2_passes; - - -#undef HANDLE_PTR -#define HANDLE_PTR(ptr,obj) do { \ - MonoObject *dst = (MonoObject*)*(ptr); \ - if (dst && !object_is_live (&dst)) { \ - dyn_array_ptr_push (&dfs_stack, obj_entry); \ - dyn_array_ptr_push (&dfs_stack, get_hash_entry (dst, NULL)); \ - } \ - } while (0) - -static void -dfs1 (HashEntry *obj_entry) -{ - HashEntry *src; - g_assert (dyn_array_ptr_size (&dfs_stack) == 0); - - dyn_array_ptr_push (&dfs_stack, NULL); - dyn_array_ptr_push (&dfs_stack, obj_entry); - - do { - MonoObject *obj; - char *start; - ++dsf1_passes; - - obj_entry = dyn_array_ptr_pop (&dfs_stack); - if (obj_entry) { - src = dyn_array_ptr_pop (&dfs_stack); - - obj = obj_entry->obj; - start = (char*)obj; - - if (src) { - //g_print ("link %s -> %s\n", sgen_safe_name (src->obj), sgen_safe_name (obj)); - add_source (obj_entry, src); - } else { - //g_print ("starting with %s\n", sgen_safe_name (obj)); - } - - if (obj_entry->is_visited) - continue; - - obj_entry->is_visited = TRUE; - - dyn_array_ptr_push (&dfs_stack, obj_entry); - /* NULL marks that the next entry is to be finished */ - dyn_array_ptr_push (&dfs_stack, NULL); - -#include "sgen-scan-object.h" - } else { - obj_entry = dyn_array_ptr_pop (&dfs_stack); - - //g_print ("finish %s\n", sgen_safe_name (obj_entry->obj)); - register_finishing_time (obj_entry, current_time++); - } - } while (dyn_array_ptr_size (&dfs_stack) > 0); -} - -static void -scc_add_xref (SCC *src, SCC *dst) -{ - g_assert (src != dst); - g_assert (src->index != dst->index); - - if (dyn_array_int_contains (&dst->xrefs, src->index)) - return; - if (src->num_bridge_entries) { - dyn_array_int_merge_one (&dst->xrefs, src->index); +init_bridge_processor (SgenBridgeProcessor *processor, const char *name) +{ + if (!strcmp ("old", name)) { + memset (processor, 0, sizeof (SgenBridgeProcessor)); + sgen_old_bridge_init (processor); + } else if (!strcmp ("new", name)) { + memset (processor, 0, sizeof (SgenBridgeProcessor)); + sgen_new_bridge_init (processor); + } else if (!strcmp ("tarjan", name)) { + memset (processor, 0, sizeof (SgenBridgeProcessor)); + sgen_tarjan_bridge_init (processor); } else { - int i; - dyn_array_int_merge (&dst->xrefs, &src->xrefs); - for (i = 0; i < dyn_array_int_size (&dst->xrefs); ++i) - g_assert (dyn_array_int_get (&dst->xrefs, i) != dst->index); + return FALSE; } + return TRUE; } -static void -scc_add_entry (SCC *scc, HashEntry *entry) +void +sgen_set_bridge_implementation (const char *name) { - g_assert (entry->scc_index < 0); - entry->scc_index = scc->index; - if (entry->is_bridge) - ++scc->num_bridge_entries; + if (!init_bridge_processor (&bridge_processor, name)) + g_warning ("Invalid value for bridge implementation, valid values are: 'new' and 'old'."); } -static DynSCCArray sccs; -static SCC *current_scc; - -static void -dfs2 (HashEntry *entry) +gboolean +sgen_is_bridge_object (MonoObject *obj) { - int i; - - g_assert (dyn_array_ptr_size (&dfs_stack) == 0); - - dyn_array_ptr_push (&dfs_stack, entry); - - do { - entry = dyn_array_ptr_pop (&dfs_stack); - ++dsf2_passes; - - if (entry->scc_index >= 0) { - if (entry->scc_index != current_scc->index) - scc_add_xref (dyn_array_scc_get_ptr (&sccs, entry->scc_index), current_scc); - continue; - } - - scc_add_entry (current_scc, entry); - - for (i = 0; i < dyn_array_ptr_size (&entry->srcs); ++i) - dyn_array_ptr_push (&dfs_stack, dyn_array_ptr_get (&entry->srcs, i)); - } while (dyn_array_ptr_size (&dfs_stack) > 0); + if ((obj->vtable->gc_bits & SGEN_GC_BIT_BRIDGE_OBJECT) != SGEN_GC_BIT_BRIDGE_OBJECT) + return FALSE; + return bridge_callbacks.is_bridge_object (obj); } -static int -compare_hash_entries (const HashEntry *e1, const HashEntry *e2) +gboolean +sgen_need_bridge_processing (void) { - return e2->finishing_time - e1->finishing_time; + return bridge_callbacks.cross_references != NULL; } -DEF_QSORT_INLINE(hash_entries, HashEntry*, compare_hash_entries) - -static unsigned long step_1, step_2, step_3, step_4, step_5, step_6, step_7, step_8; -static int fist_pass_links, second_pass_links, sccs_links; -static int max_sccs_links = 0; - -void -sgen_bridge_register_finalized_object (MonoObject *obj) +static gboolean +compare_bridge_processors (void) { - g_assert (sgen_need_bridge_processing ()); - dyn_array_ptr_push (®istered_bridges, obj); + return compare_to_bridge_processor.reset_data != NULL; } +/* Dispatch wrappers */ void sgen_bridge_reset_data (void) { - dyn_array_ptr_set_size (®istered_bridges, 0); + bridge_processor.reset_data (); + if (compare_bridge_processors ()) + compare_to_bridge_processor.reset_data (); } void sgen_bridge_processing_stw_step (void) { - int i; - int bridge_count; - SGEN_TV_DECLARE (atv); - SGEN_TV_DECLARE (btv); - - if (!dyn_array_ptr_size (®istered_bridges)) - return; - /* * bridge_processing_in_progress must be set with the world * stopped. If not there would be race conditions. */ bridge_processing_in_progress = TRUE; - SGEN_TV_GETTIME (btv); - - /* first DFS pass */ - - dyn_array_ptr_init (&dfs_stack); - dyn_array_int_init (&merge_array); - - current_time = 0; - /* - First we insert all bridges into the hash table and then we do dfs1. - - It must be done in 2 steps since the bridge arrays doesn't come in reverse topological order, - which means that we can have entry N pointing to entry N + 1. - - If we dfs1 entry N before N + 1 is registered we'll not consider N + 1 for this bridge - pass and not create the required xref between the two. - */ - bridge_count = dyn_array_ptr_size (®istered_bridges); - for (i = 0; i < bridge_count ; ++i) - register_bridge_object (dyn_array_ptr_get (®istered_bridges, i)); - - for (i = 0; i < bridge_count; ++i) - dfs1 (get_hash_entry (dyn_array_ptr_get (®istered_bridges, i), NULL)); - - SGEN_TV_GETTIME (atv); - step_2 = SGEN_TV_ELAPSED (btv, atv); + bridge_processor.processing_stw_step (); + if (compare_bridge_processors ()) + compare_to_bridge_processor.processing_stw_step (); } static mono_bool @@ -711,172 +160,13 @@ is_bridge_object_alive (MonoObject *obj, void *data) return *value; } -void -sgen_bridge_processing_finish (int generation) +static void +null_weak_links_to_dead_objects (SgenBridgeProcessor *processor, int generation) { int i, j; - int num_sccs, num_xrefs; - int max_entries, max_xrefs; - int hash_table_size, sccs_size; - MonoObject *obj; - HashEntry *entry; - int num_registered_bridges; - HashEntry **all_entries; - MonoGCBridgeSCC **api_sccs; - MonoGCBridgeXRef *api_xrefs; + int num_sccs = processor->num_sccs; + MonoGCBridgeSCC **api_sccs = processor->api_sccs; SgenHashTable alive_hash = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_ALIVE_HASH_TABLE, INTERNAL_MEM_BRIDGE_ALIVE_HASH_TABLE_ENTRY, 1, mono_aligned_addr_hash, NULL); - SGEN_TV_DECLARE (atv); - SGEN_TV_DECLARE (btv); - - if (!dyn_array_ptr_size (®istered_bridges)) - return; - - g_assert (bridge_processing_in_progress); - - SGEN_TV_GETTIME (atv); - - /* alloc and fill array of all entries */ - - all_entries = sgen_alloc_internal_dynamic (sizeof (HashEntry*) * hash_table.num_entries, INTERNAL_MEM_BRIDGE_DATA, TRUE); - - j = 0; - SGEN_HASH_TABLE_FOREACH (&hash_table, obj, entry) { - g_assert (entry->finishing_time >= 0); - all_entries [j++] = entry; - fist_pass_links += dyn_array_ptr_size (&entry->srcs); - } SGEN_HASH_TABLE_FOREACH_END; - g_assert (j == hash_table.num_entries); - hash_table_size = hash_table.num_entries; - - /* sort array according to decreasing finishing time */ - qsort_hash_entries (all_entries, hash_table.num_entries); - - SGEN_TV_GETTIME (btv); - step_3 = SGEN_TV_ELAPSED (atv, btv); - - /* second DFS pass */ - - dyn_array_scc_init (&sccs); - for (i = 0; i < hash_table.num_entries; ++i) { - HashEntry *entry = all_entries [i]; - if (entry->scc_index < 0) { - int index = dyn_array_scc_size (&sccs); - current_scc = dyn_array_scc_add (&sccs); - current_scc->index = index; - current_scc->num_bridge_entries = 0; - current_scc->api_index = -1; - dyn_array_int_init (¤t_scc->xrefs); - - dfs2 (entry); - } - } - - sccs_size = dyn_array_scc_size (&sccs); - - for (i = 0; i < hash_table.num_entries; ++i) { - HashEntry *entry = all_entries [i]; - second_pass_links += dyn_array_ptr_size (&entry->srcs); - } - - SGEN_TV_GETTIME (atv); - step_4 = SGEN_TV_ELAPSED (btv, atv); - - //g_print ("%d sccs\n", sccs.size); - - dyn_array_ptr_uninit (&dfs_stack); - - /* init data for callback */ - - num_sccs = 0; - for (i = 0; i < dyn_array_scc_size (&sccs); ++i) { - SCC *scc = dyn_array_scc_get_ptr (&sccs, i); - g_assert (scc->index == i); - if (scc->num_bridge_entries) - ++num_sccs; - sccs_links += dyn_array_int_size (&scc->xrefs); - max_sccs_links = MAX (max_sccs_links, dyn_array_int_size (&scc->xrefs)); - } - - api_sccs = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC*) * num_sccs, INTERNAL_MEM_BRIDGE_DATA, TRUE); - num_xrefs = 0; - j = 0; - for (i = 0; i < dyn_array_scc_size (&sccs); ++i) { - SCC *scc = dyn_array_scc_get_ptr (&sccs, i); - if (!scc->num_bridge_entries) - continue; - - api_sccs [j] = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC) + sizeof (MonoObject*) * scc->num_bridge_entries, INTERNAL_MEM_BRIDGE_DATA, TRUE); - api_sccs [j]->is_alive = FALSE; - api_sccs [j]->num_objs = scc->num_bridge_entries; - scc->num_bridge_entries = 0; - scc->api_index = j++; - - num_xrefs += dyn_array_int_size (&scc->xrefs); - } - - SGEN_HASH_TABLE_FOREACH (&hash_table, obj, entry) { - if (entry->is_bridge) { - SCC *scc = dyn_array_scc_get_ptr (&sccs, entry->scc_index); - api_sccs [scc->api_index]->objs [scc->num_bridge_entries++] = entry->obj; - } - } SGEN_HASH_TABLE_FOREACH_END; - - api_xrefs = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeXRef) * num_xrefs, INTERNAL_MEM_BRIDGE_DATA, TRUE); - j = 0; - for (i = 0; i < dyn_array_scc_size (&sccs); ++i) { - int k; - SCC *scc = dyn_array_scc_get_ptr (&sccs, i); - if (!scc->num_bridge_entries) - continue; - for (k = 0; k < dyn_array_int_size (&scc->xrefs); ++k) { - SCC *src_scc = dyn_array_scc_get_ptr (&sccs, dyn_array_int_get (&scc->xrefs, k)); - if (!src_scc->num_bridge_entries) - continue; - api_xrefs [j].src_scc_index = src_scc->api_index; - api_xrefs [j].dst_scc_index = scc->api_index; - ++j; - } - } - - SGEN_TV_GETTIME (btv); - step_5 = SGEN_TV_ELAPSED (atv, btv); - - /* free data */ - - j = 0; - max_entries = max_xrefs = 0; - for (i = 0; i < dyn_array_scc_size (&sccs); ++i) { - SCC *scc = dyn_array_scc_get_ptr (&sccs, i); - if (scc->num_bridge_entries) - ++j; - if (scc->num_bridge_entries > max_entries) - max_entries = scc->num_bridge_entries; - if (dyn_array_int_size (&scc->xrefs) > max_xrefs) - max_xrefs = dyn_array_int_size (&scc->xrefs); - dyn_array_int_uninit (&scc->xrefs); - - } - dyn_array_scc_uninit (&sccs); - - sgen_free_internal_dynamic (all_entries, sizeof (HashEntry*) * hash_table.num_entries, INTERNAL_MEM_BRIDGE_DATA); - - free_data (); - /* Empty the registered bridges array */ - num_registered_bridges = dyn_array_ptr_size (®istered_bridges); - dyn_array_ptr_set_size (®istered_bridges, 0); - - SGEN_TV_GETTIME (atv); - step_6 = SGEN_TV_ELAPSED (btv, atv); - - //g_print ("%d sccs containing bridges - %d max bridge objects - %d max xrefs\n", j, max_entries, max_xrefs); - - /* callback */ - - bridge_callbacks.cross_references (num_sccs, api_sccs, num_xrefs, api_xrefs); - - /* Release for finalization those objects we no longer care. */ - SGEN_TV_GETTIME (btv); - step_7 = SGEN_TV_ELAPSED (atv, btv); for (i = 0; i < num_sccs; ++i) { unsigned char alive = api_sccs [i]->is_alive ? 1 : 0; @@ -896,8 +186,16 @@ sgen_bridge_processing_finish (int generation) sgen_null_links_with_predicate (GENERATION_OLD, is_bridge_object_alive, &alive_hash); sgen_hash_table_clean (&alive_hash); +} - /* free callback data */ +static void +free_callback_data (SgenBridgeProcessor *processor) +{ + int i; + int num_sccs = processor->num_sccs; + int num_xrefs = processor->num_xrefs; + MonoGCBridgeSCC **api_sccs = processor->api_sccs; + MonoGCBridgeXRef *api_xrefs = processor->api_xrefs; for (i = 0; i < num_sccs; ++i) { sgen_free_internal_dynamic (api_sccs [i], @@ -908,49 +206,77 @@ sgen_bridge_processing_finish (int generation) sgen_free_internal_dynamic (api_xrefs, sizeof (MonoGCBridgeXRef) * num_xrefs, INTERNAL_MEM_BRIDGE_DATA); - SGEN_TV_GETTIME (atv); - step_8 = SGEN_TV_ELAPSED (btv, atv); + processor->num_sccs = 0; + processor->api_sccs = NULL; + processor->num_xrefs = 0; + processor->api_xrefs = NULL; +} + +void +sgen_bridge_processing_finish (int generation) +{ + bridge_processor.processing_build_callback_data (generation); + if (compare_bridge_processors ()) + compare_to_bridge_processor.processing_build_callback_data (generation); + + if (bridge_processor.num_sccs == 0) { + g_assert (bridge_processor.num_xrefs == 0); + goto after_callback; + } + + bridge_callbacks.cross_references (bridge_processor.num_sccs, bridge_processor.api_sccs, + bridge_processor.num_xrefs, bridge_processor.api_xrefs); + + if (compare_bridge_processors ()) + sgen_compare_bridge_processor_results (&bridge_processor, &compare_to_bridge_processor); + + null_weak_links_to_dead_objects (&bridge_processor, generation); - mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "GC_BRIDGE num-objects %d num_hash_entries %d sccs size %d init %.2fms df1 %.2fms sort %.2fms dfs2 %.2fms setup-cb %.2fms free-data %.2fms user-cb %.2fms clenanup %.2fms links %d/%d/%d/%d dfs passes %d/%d", - num_registered_bridges, hash_table_size, dyn_array_scc_size (&sccs), - step_1 / 1000.0f, - step_2 / 1000.0f, - step_3 / 1000.0f, - step_4 / 1000.0f, - step_5 / 1000.0f, - step_6 / 1000.0f, - step_7 / 1000.0f, - step_8 / 1000.f, - fist_pass_links, second_pass_links, sccs_links, max_sccs_links, - dsf1_passes, dsf2_passes); + free_callback_data (&bridge_processor); + if (compare_bridge_processors ()) + free_callback_data (&compare_to_bridge_processor); - step_1 = 0; /* We must cleanup since this value is used as an accumulator. */ + after_callback: + bridge_processor.processing_after_callback (generation); + if (compare_bridge_processors ()) + compare_to_bridge_processor.processing_after_callback (generation); bridge_processing_in_progress = FALSE; } +MonoGCBridgeObjectKind +sgen_bridge_class_kind (MonoClass *class) +{ + return bridge_processor.class_kind (class); +} + void -sgen_bridge_describe_pointer (MonoObject *obj) +sgen_bridge_register_finalized_object (MonoObject *obj) { - HashEntry *entry; - int i; + bridge_processor.register_finalized_object (obj); + if (compare_bridge_processors ()) + compare_to_bridge_processor.register_finalized_object (obj); +} - for (i = 0; i < dyn_array_ptr_size (®istered_bridges); ++i) { - if (obj == dyn_array_ptr_get (®istered_bridges, i)) { - printf ("Pointer is a registered bridge object.\n"); - break; - } - } +void +sgen_bridge_describe_pointer (MonoObject *obj) +{ + if (bridge_processor.describe_pointer) + bridge_processor.describe_pointer (obj); +} - entry = sgen_hash_table_lookup (&hash_table, obj); - if (!entry) +static void +set_dump_prefix (const char *prefix) +{ + if (!bridge_processor.set_dump_prefix) { + fprintf (stderr, "Warning: Bridge implementation does not support dumping - ignoring.\n"); return; + } - printf ("Bridge hash table entry %p:\n", entry); - printf (" is bridge: %d\n", (int)entry->is_bridge); - printf (" is visited: %d\n", (int)entry->is_visited); + bridge_processor.set_dump_prefix (prefix); } +/* Test support code */ static const char *bridge_class; static MonoGCBridgeObjectKind @@ -1066,8 +392,8 @@ bridge_test_cross_reference2 (int num_sccs, MonoGCBridgeSCC **sccs, int num_xref sccs [i]->is_alive = TRUE; } -void -sgen_register_test_bridge_callbacks (const char *bridge_class_name) +static void +register_test_bridge_callbacks (const char *bridge_class_name) { MonoGCBridgeCallbacks callbacks; callbacks.bridge_version = SGEN_BRIDGE_VERSION; @@ -1078,4 +404,40 @@ sgen_register_test_bridge_callbacks (const char *bridge_class_name) bridge_class = bridge_class_name + (bridge_class_name[0] == '2' ? 1 : 0); } +gboolean +sgen_bridge_handle_gc_debug (const char *opt) +{ + if (g_str_has_prefix (opt, "bridge=")) { + opt = strchr (opt, '=') + 1; + register_test_bridge_callbacks (g_strdup (opt)); + } else if (!strcmp (opt, "enable-bridge-accounting")) { + bridge_processor.enable_accounting (); + } else if (g_str_has_prefix (opt, "bridge-dump=")) { + char *prefix = strchr (opt, '=') + 1; + set_dump_prefix (prefix); + } else if (g_str_has_prefix (opt, "bridge-compare-to=")) { + const char *name = strchr (opt, '=') + 1; + if (init_bridge_processor (&compare_to_bridge_processor, name)) { + if (compare_to_bridge_processor.reset_data == bridge_processor.reset_data) { + g_warning ("Cannot compare bridge implementation to itself - ignoring."); + memset (&compare_to_bridge_processor, 0, sizeof (SgenBridgeProcessor)); + } + } else { + g_warning ("Invalid bridge implementation to compare against - ignoring."); + } + } else { + return FALSE; + } + return TRUE; +} + +void +sgen_bridge_print_gc_debug_usage (void) +{ + fprintf (stderr, " bridge=\n"); + fprintf (stderr, " enable-bridge-accounting\n"); + fprintf (stderr, " bridge-dump=\n"); + fprintf (stderr, " bridge-compare-to=\n"); +} + #endif