-/* 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--;
-
- add_or_remove_disappearing_link ((MonoObject*)copy, link,
- track, 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;
- }
- }
-}
-
-/* LOCKING: requires that the GC lock is held */
-static void
-null_links_for_domain (MonoDomain *domain, int generation)
-{
- 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;
- for (i = 0; i < disappearing_link_hash_size; ++i) {
- prev = NULL;
- for (entry = disappearing_link_hash [i]; entry; ) {
- char *object = DISLINK_OBJECT (entry);
- if (object && !((MonoObject*)object)->vtable) {
- DisappearingLink *next = entry->next;
-
- if (prev)
- prev->next = next;
- else
- disappearing_link_hash [i] = next;
-
- if (*(entry->link)) {
- *(entry->link) = NULL;
- g_warning ("Disappearing link %p not freed", entry->link);
- } else {
- mono_sgen_free_internal (entry, INTERNAL_MEM_DISLINK);
- }
-
- entry = next;
- continue;
- }
- prev = entry;
- entry = entry->next;
- }
- }
-}
-
-/* LOCKING: requires that the GC lock is held */
-static int
-finalizers_for_domain (MonoDomain *domain, MonoObject **out_array, int out_size,
- FinalizeEntryHashTable *hash_table)
-{
- FinalizeEntry **finalizable_hash = hash_table->table;
- mword finalizable_hash_size = hash_table->size;
- FinalizeEntry *entry, *prev;
- int i, count;
-
- if (no_finalize || !out_size || !out_array)
- return 0;
- count = 0;
- for (i = 0; i < finalizable_hash_size; ++i) {
- prev = NULL;
- for (entry = finalizable_hash [i]; entry;) {
- if (mono_object_domain (entry->object) == domain) {
- FinalizeEntry *next;
- /* remove and put in out_array */
- if (prev)
- prev->next = entry->next;
- else
- finalizable_hash [i] = entry->next;
- next = entry->next;
- hash_table->num_registered--;
- out_array [count ++] = entry->object;
- DEBUG (5, fprintf (gc_debug_file, "Collecting object for finalization: %p (%s) (%d/%d)\n", entry->object, safe_name (entry->object), num_ready_finalizers, hash_table->num_registered));
- entry = next;
- if (count == out_size)
- return count;
- continue;
- }
- prev = entry;
- entry = entry->next;
- }
- }
- return count;
-}
-
-/**
- * mono_gc_finalizers_for_domain:
- * @domain: the unloading appdomain
- * @out_array: output array
- * @out_size: size of output array
- *
- * Store inside @out_array up to @out_size objects that belong to the unloading
- * appdomain @domain. Returns the number of stored items. Can be called repeteadly
- * until it returns 0.
- * The items are removed from the finalizer data structure, so the caller is supposed
- * to finalize them.
- * @out_array should be on the stack to allow the GC to know the objects are still alive.
- */
-int
-mono_gc_finalizers_for_domain (MonoDomain *domain, MonoObject **out_array, int out_size)
-{
- int result;
-
- LOCK_GC;
- result = finalizers_for_domain (domain, out_array, out_size, &minor_finalizable_hash);
- if (result < out_size) {
- result += finalizers_for_domain (domain, out_array + result, out_size - result,
- &major_finalizable_hash);
- }
- UNLOCK_GC;
-
- return result;
-}
-
-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);
- LOCK_GC;
- 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);
- }
- UNLOCK_GC;
- return;
- }
- prev = entry;
- }
- if (!user_data) {
- /* request to deregister, but already out of the list */
- UNLOCK_GC;
- 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)));
- UNLOCK_GC;
-}
-
-void
-mono_gc_register_for_finalization (MonoObject *obj, void *user_data)
-{
- if (ptr_in_nursery (obj))
- register_for_finalization (obj, user_data, GENERATION_NURSERY);
- else
- register_for_finalization (obj, user_data, GENERATION_OLD);
-}
-
-static void
-rehash_dislink (DisappearingLinkHashTable *hash_table)
-{
- DisappearingLink **disappearing_link_hash = hash_table->table;
- int disappearing_link_hash_size = hash_table->size;
- int i;
- unsigned int hash;
- DisappearingLink **new_hash;
- DisappearingLink *entry, *next;
- int new_size = g_spaced_primes_closest (hash_table->num_links);
-
- new_hash = mono_sgen_alloc_internal_dynamic (new_size * sizeof (DisappearingLink*), INTERNAL_MEM_DISLINK_TABLE);
- for (i = 0; i < disappearing_link_hash_size; ++i) {
- for (entry = disappearing_link_hash [i]; entry; entry = next) {
- hash = mono_aligned_addr_hash (entry->link) % new_size;
- next = entry->next;
- entry->next = new_hash [hash];
- new_hash [hash] = entry;
- }
- }
- mono_sgen_free_internal_dynamic (disappearing_link_hash,
- disappearing_link_hash_size * sizeof (DisappearingLink*), INTERNAL_MEM_DISLINK_TABLE);
- hash_table->table = new_hash;
- hash_table->size = new_size;
-}
-
-/* LOCKING: assumes the GC lock is held */
-static void
-add_or_remove_disappearing_link (MonoObject *obj, void **link, gboolean track, int generation)
-{
- DisappearingLinkHashTable *hash_table = get_dislink_hash_table (generation);
- DisappearingLink *entry, *prev;
- unsigned int hash;
- DisappearingLink **disappearing_link_hash = hash_table->table;
- int disappearing_link_hash_size = hash_table->size;
-
- if (hash_table->num_links >= disappearing_link_hash_size * 2) {
- rehash_dislink (hash_table);
- disappearing_link_hash = hash_table->table;
- disappearing_link_hash_size = hash_table->size;
- }
- /* FIXME: add check that link is not in the heap */
- hash = mono_aligned_addr_hash (link) % disappearing_link_hash_size;
- entry = disappearing_link_hash [hash];
- prev = NULL;
- for (; entry; entry = entry->next) {
- /* link already added */
- if (link == entry->link) {
- /* NULL obj means remove */
- if (obj == NULL) {
- if (prev)
- prev->next = entry->next;
- else
- disappearing_link_hash [hash] = entry->next;
- hash_table->num_links--;
- DEBUG (5, fprintf (gc_debug_file, "Removed dislink %p (%d) from %s table\n", entry, hash_table->num_links, generation_name (generation)));
- mono_sgen_free_internal (entry, INTERNAL_MEM_DISLINK);
- *link = NULL;
- } else {
- *link = HIDE_POINTER (obj, track); /* we allow the change of object */
- }
- return;
- }
- prev = entry;
- }
- if (obj == NULL)
- return;
- entry = mono_sgen_alloc_internal (INTERNAL_MEM_DISLINK);
- *link = HIDE_POINTER (obj, track);
- entry->link = link;
- entry->next = disappearing_link_hash [hash];
- disappearing_link_hash [hash] = entry;
- hash_table->num_links++;
- DEBUG (5, fprintf (gc_debug_file, "Added dislink %p for object: %p (%s) at %p to %s table\n", entry, obj, obj->vtable->klass->name, link, generation_name (generation)));
-}
-
-/* LOCKING: assumes the GC lock is held */
-static void
-mono_gc_register_disappearing_link (MonoObject *obj, void **link, gboolean track)
-{
- add_or_remove_disappearing_link (NULL, link, FALSE, GENERATION_NURSERY);
- add_or_remove_disappearing_link (NULL, link, FALSE, GENERATION_OLD);
- if (obj) {
- if (ptr_in_nursery (obj))
- add_or_remove_disappearing_link (obj, link, track, GENERATION_NURSERY);
- else
- add_or_remove_disappearing_link (obj, link, track, GENERATION_OLD);
- }
-}
-