/* LOCKING: requires that the GC lock is held */ static void collect_bridge_objects (CopyOrMarkObjectFunc copy_func, char *start, char *end, int generation, GrayQueue *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 (!((char*)object >= start && (char*)object < end && !major_collector.is_object_live ((char*)object))) continue; /* Nursery says the object is dead. */ if (!object_is_fin_ready (object)) continue; if (!mono_sgen_is_bridge_object (object)) continue; copy = (char*)object; copy_func ((void**)©, queue); mono_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 */ mono_sgen_hash_table_replace (&major_finalizable_hash, tagged_object_apply (copy, tag), NULL); DEBUG (5, fprintf (gc_debug_file, "Promoting finalization of object %p (%s) (was at %p) to major table\n", copy, safe_name (copy), object)); continue; } else { /* update pointer */ DEBUG (5, fprintf (gc_debug_file, "Updating object for finalization: %p (%s) (was at %p)\n", copy, safe_name (copy), object)); SGEN_HASH_TABLE_FOREACH_SET_KEY (tagged_object_apply (copy, tag)); } } SGEN_HASH_TABLE_FOREACH_END;
/* LOCKING: requires that the GC lock is held */ static void finalize_in_range (CopyOrMarkObjectFunc copy_func, char *start, char *end, int generation, GrayQueue *queue) { FinalizeEntryHashTable *hash_table = get_finalize_entry_hash_table (generation); FinalizeEntry *entry, *prev; int i; FinalizeEntry **finalizable_hash = hash_table->table; mword finalizable_hash_size = hash_table->size; if (no_finalize) return; for (i = 0; i < finalizable_hash_size; ++i) { prev = NULL; for (entry = finalizable_hash [i]; entry;) { if ((char*)entry->object >= start && (char*)entry->object < end && !major_collector.is_object_live (entry->object)) { gboolean is_fin_ready = object_is_fin_ready (entry->object); char *copy = entry->object; copy_func ((void**)©, queue); if (is_fin_ready) { char *from; FinalizeEntry *next; /* remove and put in fin_ready_list */ if (prev) prev->next = entry->next; else finalizable_hash [i] = entry->next; next = entry->next; num_ready_finalizers++; hash_table->num_registered--; queue_finalization_entry (entry); bridge_register_finalized_object ((MonoObject*)copy); /* Make it survive */ from = entry->object; entry->object = copy; DEBUG (5, fprintf (gc_debug_file, "Queueing object for finalization: %p (%s) (was at %p) (%d/%d)\n", entry->object, safe_name (entry->object), from, num_ready_finalizers, hash_table->num_registered)); entry = next; continue; } else { char *from = entry->object; if (hash_table == &minor_finalizable_hash && !ptr_in_nursery (copy)) { FinalizeEntry *next = entry->next; unsigned int major_hash; /* remove from the list */ if (prev) prev->next = entry->next; else finalizable_hash [i] = entry->next; hash_table->num_registered--; entry->object = copy; /* insert it into the major hash */ rehash_fin_table_if_necessary (&major_finalizable_hash); major_hash = mono_object_hash ((MonoObject*) copy) % major_finalizable_hash.size; entry->next = major_finalizable_hash.table [major_hash]; major_finalizable_hash.table [major_hash] = entry; major_finalizable_hash.num_registered++; DEBUG (5, fprintf (gc_debug_file, "Promoting finalization of object %p (%s) (was at %p) to major table\n", copy, safe_name (copy), from)); entry = next; continue; } else { /* update pointer */ DEBUG (5, fprintf (gc_debug_file, "Updating object for finalization: %p (%s) (was at %p)\n", entry->object, safe_name (entry->object), from)); entry->object = copy; } } } prev = entry; entry = entry->next; } } }
/* LOCKING: requires that the GC lock is held */ static void null_link_in_range (CopyOrMarkObjectFunc copy_func, char *start, char *end, int generation, gboolean before_finalization, GrayQueue *queue) { DisappearingLinkHashTable *hash = get_dislink_hash_table (generation); DisappearingLink **disappearing_link_hash = hash->table; int disappearing_link_hash_size = hash->size; DisappearingLink *entry, *prev; int i; if (!hash->num_links) return; for (i = 0; i < disappearing_link_hash_size; ++i) { prev = NULL; for (entry = disappearing_link_hash [i]; entry;) { char *object; gboolean track = DISLINK_TRACK (entry); /* * Tracked references are processed after * finalization handling whereas standard weak * references are processed before. If an * object is still not marked after finalization * handling it means that it either doesn't have * a finalizer or the finalizer has already run, * so we must null a tracking reference. */ if (track == before_finalization) { prev = entry; entry = entry->next; continue; } object = DISLINK_OBJECT (entry); if (object >= start && object < end && !major_collector.is_object_live (object)) { if (object_is_fin_ready (object)) { void **p = entry->link; DisappearingLink *old; *p = NULL; /* remove from list */ if (prev) prev->next = entry->next; else disappearing_link_hash [i] = entry->next; DEBUG (5, fprintf (gc_debug_file, "Dislink nullified at %p to GCed object %p\n", p, object)); old = entry->next; mono_sgen_free_internal (entry, INTERNAL_MEM_DISLINK); entry = old; hash->num_links--; continue; } else { char *copy = object; copy_func ((void**)©, queue); /* Update pointer if it's moved. If the object * has been moved out of the nursery, we need to * remove the link from the minor hash table to * the major one. * * FIXME: what if an object is moved earlier? */ if (hash == &minor_disappearing_link_hash && !ptr_in_nursery (copy)) { void **link = entry->link; DisappearingLink *old; /* remove from list */ if (prev) prev->next = entry->next; else disappearing_link_hash [i] = entry->next; old = entry->next; mono_sgen_free_internal (entry, INTERNAL_MEM_DISLINK); entry = old; hash->num_links--; g_assert (copy); *link = HIDE_POINTER (copy, track); add_or_remove_disappearing_link ((MonoObject*)copy, link, GENERATION_OLD); DEBUG (5, fprintf (gc_debug_file, "Upgraded dislink at %p to major because object %p moved to %p\n", link, object, copy)); continue; } else { *entry->link = HIDE_POINTER (copy, track); DEBUG (5, fprintf (gc_debug_file, "Updated dislink at %p to %p\n", entry->link, DISLINK_OBJECT (entry))); } } } prev = entry; entry = entry->next; } } }