static void* dyn_array_ptr_pop (DynPtrArray *da) { int size = da->array.size; void *p; g_assert (size > 0); if (da->array.capacity == 1) { p = dyn_array_ptr_get (da, 0); dyn_array_init (&da->array); } else { g_assert (da->array.capacity > 1); dyn_array_ensure_independent (&da->array, sizeof (void*)); p = dyn_array_ptr_get (da, size - 1); --da->array.size; } return p; }
static gboolean dyn_array_ptr_contains (DynPtrArray *da, void *x) { int i; for (i = 0; i < dyn_array_ptr_size (da); ++i) if (dyn_array_ptr_get (da, i) == x) return TRUE; return FALSE; }
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; }
static void* dyn_array_ptr_pop (DynPtrArray *da) { int size = da->array.size; void *p; g_assert (size > 0); #ifdef OPTIMIZATION_SINGLETON_DYN_ARRAY if (da->array.capacity == 1) { p = dyn_array_ptr_get (da, 0); dyn_array_init (&da->array); } else #endif { g_assert (da->array.capacity > 1); dyn_array_ensure_independent (&da->array, sizeof (void*)); p = dyn_array_ptr_get (da, size - 1); --da->array.size; } return p; }
static gboolean match_colors (DynPtrArray *a, DynPtrArray *b) { int i; if (dyn_array_ptr_size (a) != dyn_array_ptr_size (b)) return FALSE; for (i = 0; i < dyn_array_ptr_size (a); ++i) { if (!dyn_array_ptr_contains (b, dyn_array_ptr_get (a, i))) return FALSE; } return TRUE; }
static void reset_xrefs (ColorData *color) { int i; for (i = 0; i < dyn_array_ptr_size (&color->other_colors); ++i) { ColorData *src = dyn_array_ptr_get (&color->other_colors, i); if (!src->visited) continue; src->visited = FALSE; if (!dyn_array_ptr_size (&src->bridges)) reset_xrefs (src); } }
static void gather_xrefs (ColorData *color) { int i; for (i = 0; i < dyn_array_ptr_size (&color->other_colors); ++i) { ColorData *src = dyn_array_ptr_get (&color->other_colors, i); if (src->visited) continue; src->visited = TRUE; if (dyn_array_ptr_size (&src->bridges)) dyn_array_ptr_add (&color_merge_array, src); else gather_xrefs (src); } }
static ColorData* reduce_color (void) { ColorData *color = NULL; int size = dyn_array_ptr_size (&color_merge_array); if (size == 0) color = NULL; else if (size == 1) { color = dyn_array_ptr_get (&color_merge_array, 0); } else color = new_color (FALSE); return color; }
static void describe_pointer (GCObject *obj) { // HashEntry *entry; int i; 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; } } // entry = sgen_hash_table_lookup (&hash_table, obj); // if (!entry) // 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); }
static ColorData* find_in_cache (int *insert_index) { HashEntry *bucket; int i, hash, size, index; size = dyn_array_ptr_size (&color_merge_array); /* Cache checking is very ineficient with a lot of elements*/ if (size > 3) return NULL; hash = 0; for (i = 0 ; i < size; ++i) hash += mix_hash ((size_t)dyn_array_ptr_get (&color_merge_array, i)); if (!hash) hash = 1; index = hash & (COLOR_CACHE_SIZE - 1); bucket = merge_cache [index]; for (i = 0; i < ELEMENTS_PER_BUCKET; ++i) { if (bucket [i].hash != hash) continue; if (match_colors (&bucket [i].color->other_colors, &color_merge_array)) { ++cache_hits; return bucket [i].color; } } //move elements to the back for (i = ELEMENTS_PER_BUCKET - 1; i > 0; --i) bucket [i] = bucket [i - 1]; ++cache_misses; *insert_index = index; bucket [0].hash = hash; return NULL; }
static void create_scc (ScanData *data) { int i; gboolean found = FALSE; gboolean found_bridge = FALSE; ColorData *color_data = NULL; for (i = dyn_array_ptr_size (&loop_stack) - 1; i >= 0; --i) { ScanData *other = dyn_array_ptr_get (&loop_stack, i); found_bridge |= other->is_bridge; if (found_bridge || other == data) break; } #if DUMP_GRAPH printf ("|SCC rooted in %s (%p) has bridge %d\n", safe_name_bridge (data->obj), data->obj, found_bridge); printf ("\tpoints-to-colors: "); for (i = 0; i < dyn_array_ptr_size (&color_merge_array); ++i) printf ("%p ", dyn_array_ptr_get (&color_merge_array, i)); printf ("\n"); printf ("loop stack: "); for (i = 0; i < dyn_array_ptr_size (&loop_stack); ++i) { ScanData *other = dyn_array_ptr_get (&loop_stack, i); printf ("(%d/%d)", other->index, other->low_index); } printf ("\n"); #endif if (found_bridge) { color_data = new_color (TRUE); ++num_colors_with_bridges; } else { color_data = reduce_color (); } while (dyn_array_ptr_size (&loop_stack) > 0) { ScanData *other = dyn_array_ptr_pop (&loop_stack); #if DUMP_GRAPH printf ("\tmember %s (%p) index %d low-index %d color %p state %d\n", safe_name_bridge (other->obj), other->obj, other->index, other->low_index, other->color, other->state); #endif other->color = color_data; switch (other->state) { case FINISHED_ON_STACK: other->state = FINISHED_OFF_STACK; break; case FINISHED_OFF_STACK: break; default: g_error ("Invalid state when building SCC %d", other->state); } if (other->is_bridge) dyn_array_ptr_add (&color_data->bridges, other->obj); if (other == data) { found = TRUE; break; } } g_assert (found); for (i = 0; i < dyn_array_ptr_size (&color_merge_array); ++i) { ColorData *cd = dyn_array_ptr_get (&color_merge_array, i); g_assert (cd->visited); cd->visited = FALSE; } dyn_array_ptr_set_size (&color_merge_array, 0); found_bridge = FALSE; }
static void processing_build_callback_data (int generation) { int j, api_index; MonoGCBridgeSCC **api_sccs; MonoGCBridgeXRef *api_xrefs; gint64 curtime; ColorBucket *cur; g_assert (bridge_processor->num_sccs == 0 && bridge_processor->num_xrefs == 0); g_assert (!bridge_processor->api_sccs && !bridge_processor->api_xrefs); if (!dyn_array_ptr_size (®istered_bridges)) return; SGEN_TV_GETTIME (curtime); /*create API objects */ #if defined (DUMP_GRAPH) printf ("***** API *****\n"); printf ("number of SCCs %d\n", num_colors_with_bridges); #endif /* This is a straightforward translation from colors to the bridge callback format. */ api_sccs = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC*) * num_colors_with_bridges, INTERNAL_MEM_BRIDGE_DATA, TRUE); api_index = xref_count = 0; for (cur = root_color_bucket; cur; cur = cur->next) { ColorData *cd; for (cd = &cur->data [0]; cd < cur->next_data; ++cd) { int bridges = dyn_array_ptr_size (&cd->bridges); if (!bridges) continue; api_sccs [api_index] = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC) + sizeof (MonoObject*) * bridges, INTERNAL_MEM_BRIDGE_DATA, TRUE); api_sccs [api_index]->is_alive = FALSE; api_sccs [api_index]->num_objs = bridges; cd->api_index = api_index; for (j = 0; j < bridges; ++j) api_sccs [api_index]->objs [j] = dyn_array_ptr_get (&cd->bridges, j); api_index++; } } scc_setup_time = step_timer (&curtime); for (cur = root_color_bucket; cur; cur = cur->next) { ColorData *cd; for (cd = &cur->data [0]; cd < cur->next_data; ++cd) { int bridges = dyn_array_ptr_size (&cd->bridges); if (!bridges) continue; dyn_array_ptr_set_size (&color_merge_array, 0); gather_xrefs (cd); reset_xrefs (cd); dyn_array_ptr_set_all (&cd->other_colors, &color_merge_array); xref_count += dyn_array_ptr_size (&cd->other_colors); } } gather_xref_time = step_timer (&curtime); #if defined (DUMP_GRAPH) printf ("TOTAL XREFS %d\n", xref_count); dump_color_table (" after xref pass", TRUE); #endif api_xrefs = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeXRef) * xref_count, INTERNAL_MEM_BRIDGE_DATA, TRUE); api_index = 0; for (cur = root_color_bucket; cur; cur = cur->next) { ColorData *src; for (src = &cur->data [0]; src < cur->next_data; ++src) { int bridges = dyn_array_ptr_size (&src->bridges); if (!bridges) continue; for (j = 0; j < dyn_array_ptr_size (&src->other_colors); ++j) { ColorData *dest = dyn_array_ptr_get (&src->other_colors, j); g_assert (dyn_array_ptr_size (&dest->bridges)); /* We flattened the color graph, so this must never happen. */ api_xrefs [api_index].src_scc_index = src->api_index; api_xrefs [api_index].dst_scc_index = dest->api_index; ++api_index; } } } g_assert (xref_count == api_index); xref_setup_time = step_timer (&curtime); #if defined (DUMP_GRAPH) printf ("---xrefs:\n"); for (i = 0; i < xref_count; ++i) printf ("\t%d -> %d\n", api_xrefs [i].src_scc_index, api_xrefs [i].dst_scc_index); #endif //FIXME move half of the cleanup to before the bridge callback? bridge_processor->num_sccs = num_colors_with_bridges; bridge_processor->api_sccs = api_sccs; bridge_processor->num_xrefs = xref_count; bridge_processor->api_xrefs = api_xrefs; }