static void null_weak_links_to_dead_objects (SgenBridgeProcessor *processor, int generation) { int i, j; 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); for (i = 0; i < num_sccs; ++i) { unsigned char alive = api_sccs [i]->is_alive ? 1 : 0; for (j = 0; j < api_sccs [i]->num_objs; ++j) { /* Build hash table for nulling weak links. */ sgen_hash_table_replace (&alive_hash, api_sccs [i]->objs [j], &alive, NULL); /* Release for finalization those objects we no longer care. */ if (!api_sccs [i]->is_alive) sgen_mark_bridge_object (api_sccs [i]->objs [j]); } } /* Null weak links to dead objects. */ sgen_null_links_if (is_bridge_object_dead, &alive_hash, GENERATION_NURSERY, FALSE); sgen_null_links_if (is_bridge_object_dead, &alive_hash, GENERATION_NURSERY, TRUE); if (generation == GENERATION_OLD) { sgen_null_links_if (is_bridge_object_dead, &alive_hash, GENERATION_OLD, FALSE); sgen_null_links_if (is_bridge_object_dead, &alive_hash, GENERATION_OLD, TRUE); } sgen_hash_table_clean (&alive_hash); }
/* LOCKING: requires that the GC lock is held */ void sgen_collect_bridge_objects (int generation, ScanCopyContext ctx) { CopyOrMarkObjectFunc copy_func = ctx.copy_func; GrayQueue *queue = ctx.queue; SgenHashTable *hash_table = get_finalize_entry_hash_table (generation); MonoObject *object; gpointer dummy; char *copy; if (no_finalize) return; SGEN_HASH_TABLE_FOREACH (hash_table, object, dummy) { int tag = tagged_object_get_tag (object); object = tagged_object_get_object (object); /* Bridge code told us to ignore this one */ if (tag == BRIDGE_OBJECT_MARKED) continue; /* Object is a bridge object and major heap says it's dead */ if (major_collector.is_object_live ((char*)object)) continue; /* Nursery says the object is dead. */ if (!sgen_gc_is_object_ready_for_finalization (object)) continue; if (!sgen_is_bridge_object (object)) continue; copy = (char*)object; copy_func ((void**)©, queue); sgen_bridge_register_finalized_object ((MonoObject*)copy); if (hash_table == &minor_finalizable_hash && !ptr_in_nursery (copy)) { /* remove from the list */ SGEN_HASH_TABLE_FOREACH_REMOVE (TRUE); /* insert it into the major hash */ sgen_hash_table_replace (&major_finalizable_hash, tagged_object_apply (copy, tag), NULL, NULL); SGEN_LOG (5, "Promoting finalization of object %p (%s) (was at %p) to major table", copy, sgen_safe_name (copy), object); continue; } else { /* update pointer */ SGEN_LOG (5, "Updating object for finalization: %p (%s) (was at %p)", copy, sgen_safe_name (copy), object); SGEN_HASH_TABLE_FOREACH_SET_KEY (tagged_object_apply (copy, tag)); } }
static gboolean sgen_compare_bridge_processor_results (SgenBridgeProcessor *a, SgenBridgeProcessor *b) { int i; SgenHashTable obj_to_a_scc = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_DEBUG, INTERNAL_MEM_BRIDGE_DEBUG, sizeof (int), mono_aligned_addr_hash, NULL); SgenHashTable b_scc_to_a_scc = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_DEBUG, INTERNAL_MEM_BRIDGE_DEBUG, sizeof (int), g_direct_hash, NULL); MonoGCBridgeXRef *a_xrefs, *b_xrefs; size_t xrefs_alloc_size; // dump_processor_state (a); // dump_processor_state (b); if (a->num_sccs != b->num_sccs) g_error ("SCCS count expected %d but got %d", a->num_sccs, b->num_sccs); if (a->num_xrefs != b->num_xrefs) g_error ("SCCS count expected %d but got %d", a->num_xrefs, b->num_xrefs); /* * First we build a hash of each object in `a` to its respective SCC index within * `a`. Along the way we also assert that no object is more than one SCC. */ for (i = 0; i < a->num_sccs; ++i) { int j; MonoGCBridgeSCC *scc = a->api_sccs [i]; g_assert (scc->num_objs > 0); for (j = 0; j < scc->num_objs; ++j) { GCObject *obj = scc->objs [j]; gboolean new_entry = sgen_hash_table_replace (&obj_to_a_scc, obj, &i, NULL); g_assert (new_entry); } } /* * Now we check whether each of the objects in `b` are in `a`, and whether the SCCs * of `b` contain the same sets of objects as those of `a`. * * While we're doing this, build a hash table to map from `b` SCC indexes to `a` SCC * indexes. */ for (i = 0; i < b->num_sccs; ++i) { MonoGCBridgeSCC *scc = b->api_sccs [i]; MonoGCBridgeSCC *a_scc; int *a_scc_index_ptr; int a_scc_index; int j; gboolean new_entry; g_assert (scc->num_objs > 0); a_scc_index_ptr = (int *)sgen_hash_table_lookup (&obj_to_a_scc, scc->objs [0]); g_assert (a_scc_index_ptr); a_scc_index = *a_scc_index_ptr; //g_print ("A SCC %d -> B SCC %d\n", a_scc_index, i); a_scc = a->api_sccs [a_scc_index]; g_assert (a_scc->num_objs == scc->num_objs); for (j = 1; j < scc->num_objs; ++j) { a_scc_index_ptr = (int *)sgen_hash_table_lookup (&obj_to_a_scc, scc->objs [j]); g_assert (a_scc_index_ptr); g_assert (*a_scc_index_ptr == a_scc_index); } new_entry = sgen_hash_table_replace (&b_scc_to_a_scc, GINT_TO_POINTER (i), &a_scc_index, NULL); g_assert (new_entry); } /* * Finally, check that we have the same xrefs. We do this by making copies of both * xref arrays, and replacing the SCC indexes in the copy for `b` with the * corresponding indexes in `a`. Then we sort both arrays and assert that they're * the same. * * At the same time, check that no xref is self-referential and that there are no * duplicate ones. */ xrefs_alloc_size = a->num_xrefs * sizeof (MonoGCBridgeXRef); a_xrefs = (MonoGCBridgeXRef *)sgen_alloc_internal_dynamic (xrefs_alloc_size, INTERNAL_MEM_BRIDGE_DEBUG, TRUE); b_xrefs = (MonoGCBridgeXRef *)sgen_alloc_internal_dynamic (xrefs_alloc_size, INTERNAL_MEM_BRIDGE_DEBUG, TRUE); memcpy (a_xrefs, a->api_xrefs, xrefs_alloc_size); for (i = 0; i < b->num_xrefs; ++i) { MonoGCBridgeXRef *xref = &b->api_xrefs [i]; int *scc_index_ptr; g_assert (xref->src_scc_index != xref->dst_scc_index); scc_index_ptr = (int *)sgen_hash_table_lookup (&b_scc_to_a_scc, GINT_TO_POINTER (xref->src_scc_index)); g_assert (scc_index_ptr); b_xrefs [i].src_scc_index = *scc_index_ptr; scc_index_ptr = (int *)sgen_hash_table_lookup (&b_scc_to_a_scc, GINT_TO_POINTER (xref->dst_scc_index)); g_assert (scc_index_ptr); b_xrefs [i].dst_scc_index = *scc_index_ptr; } qsort (a_xrefs, a->num_xrefs, sizeof (MonoGCBridgeXRef), compare_xrefs); qsort (b_xrefs, a->num_xrefs, sizeof (MonoGCBridgeXRef), compare_xrefs); for (i = 0; i < a->num_xrefs; ++i) { g_assert (a_xrefs [i].src_scc_index == b_xrefs [i].src_scc_index); g_assert (a_xrefs [i].dst_scc_index == b_xrefs [i].dst_scc_index); } sgen_hash_table_clean (&obj_to_a_scc); sgen_hash_table_clean (&b_scc_to_a_scc); sgen_free_internal_dynamic (a_xrefs, xrefs_alloc_size, INTERNAL_MEM_BRIDGE_DEBUG); sgen_free_internal_dynamic (b_xrefs, xrefs_alloc_size, INTERNAL_MEM_BRIDGE_DEBUG); return TRUE; }
/* LOCKING: requires that the GC lock is held */ void sgen_collect_bridge_objects (int generation, ScanCopyContext ctx) { CopyOrMarkObjectFunc copy_func = ctx.ops->copy_or_mark_object; GrayQueue *queue = ctx.queue; SgenHashTable *hash_table = get_finalize_entry_hash_table (generation); GCObject *object; gpointer dummy G_GNUC_UNUSED; GCObject *copy; SgenPointerQueue moved_fin_objects; sgen_pointer_queue_init (&moved_fin_objects, INTERNAL_MEM_TEMPORARY); if (no_finalize) return; SGEN_HASH_TABLE_FOREACH (hash_table, GCObject *, object, gpointer, dummy) { int tag = tagged_object_get_tag (object); object = tagged_object_get_object (object); /* Bridge code told us to ignore this one */ if (tag == BRIDGE_OBJECT_MARKED) continue; /* Object is a bridge object and major heap says it's dead */ if (major_collector.is_object_live (object)) continue; /* Nursery says the object is dead. */ if (!sgen_gc_is_object_ready_for_finalization (object)) continue; if (!sgen_client_bridge_is_bridge_object (object)) continue; copy = object; copy_func (©, queue); sgen_client_bridge_register_finalized_object (copy); if (hash_table == &minor_finalizable_hash && !ptr_in_nursery (copy)) { /* remove from the list */ SGEN_HASH_TABLE_FOREACH_REMOVE (TRUE); /* insert it into the major hash */ sgen_hash_table_replace (&major_finalizable_hash, tagged_object_apply (copy, tag), NULL, NULL); SGEN_LOG (5, "Promoting finalization of object %p (%s) (was at %p) to major table", copy, sgen_client_vtable_get_name (SGEN_LOAD_VTABLE (copy)), object); continue; } else if (copy != object) { /* update pointer */ SGEN_HASH_TABLE_FOREACH_REMOVE (TRUE); /* register for reinsertion */ sgen_pointer_queue_add (&moved_fin_objects, tagged_object_apply (copy, tag)); SGEN_LOG (5, "Updating object for finalization: %p (%s) (was at %p)", copy, sgen_client_vtable_get_name (SGEN_LOAD_VTABLE (copy)), object); continue; } } SGEN_HASH_TABLE_FOREACH_END;