/* LOCKING: requires that the GC lock is held */ void sgen_mark_bridge_object (MonoObject *obj) { SgenHashTable *hash_table = get_finalize_entry_hash_table (ptr_in_nursery (obj) ? GENERATION_NURSERY : GENERATION_OLD); sgen_hash_table_set_key (hash_table, obj, tagged_object_apply (obj, BRIDGE_OBJECT_MARKED)); }
/* 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)); } }
/* 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 register_for_finalization (MonoObject *obj, void *user_data, int generation) { FinalizeEntryHashTable *hash_table = get_finalize_entry_hash_table (generation); FinalizeEntry **finalizable_hash; mword finalizable_hash_size; FinalizeEntry *entry, *prev; unsigned int hash; if (no_finalize) return; g_assert (user_data == NULL || user_data == mono_gc_run_finalize); hash = mono_object_hash (obj); rehash_fin_table_if_necessary (hash_table); finalizable_hash = hash_table->table; finalizable_hash_size = hash_table->size; hash %= finalizable_hash_size; prev = NULL; for (entry = finalizable_hash [hash]; entry; entry = entry->next) { if (entry->object == obj) { if (!user_data) { /* remove from the list */ if (prev) prev->next = entry->next; else finalizable_hash [hash] = entry->next; hash_table->num_registered--; DEBUG (5, fprintf (gc_debug_file, "Removed finalizer %p for object: %p (%s) (%d)\n", entry, obj, obj->vtable->klass->name, hash_table->num_registered)); mono_sgen_free_internal (entry, INTERNAL_MEM_FINALIZE_ENTRY); } return; } prev = entry; } if (!user_data) { /* request to deregister, but already out of the list */ return; } entry = mono_sgen_alloc_internal (INTERNAL_MEM_FINALIZE_ENTRY); entry->object = obj; entry->next = finalizable_hash [hash]; finalizable_hash [hash] = entry; hash_table->num_registered++; DEBUG (5, fprintf (gc_debug_file, "Added finalizer %p for object: %p (%s) (%d) to %s table\n", entry, obj, obj->vtable->klass->name, hash_table->num_registered, generation_name (generation))); }
/* 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;
/* 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; } } }