Merge pull request #637 from LogosBible/enetdown
[mono.git] / mono / metadata / sgen-bridge.c
index 91b00436de524519a972ccfc6b8899acfe6fda38..40448b28696b9b1f117cae7a8ae86aa38491c07a 100644 (file)
@@ -45,6 +45,7 @@
 
 #include "sgen-gc.h"
 #include "sgen-bridge.h"
+#include "sgen-hash-table.h"
 #include "utils/mono-logger-internal.h"
 #include "utils/mono-time.h"
 
@@ -107,7 +108,7 @@ dyn_array_ensure_capacity (DynArray *da, int capacity)
        while (capacity > da->capacity)
                da->capacity *= 2;
 
-       new_data = sgen_alloc_internal_dynamic (da->elem_size * da->capacity, INTERNAL_MEM_BRIDGE_DATA);
+       new_data = sgen_alloc_internal_dynamic (da->elem_size * da->capacity, INTERNAL_MEM_BRIDGE_DATA, TRUE);
        memcpy (new_data, da->data, da->elem_size * da->size);
        sgen_free_internal_dynamic (da->data, da->elem_size * old_capacity, INTERNAL_MEM_BRIDGE_DATA);
        da->data = new_data;
@@ -270,12 +271,26 @@ typedef struct _SCC {
        DynArray xrefs;         /* these are incoming, not outgoing */
 } SCC;
 
-static SgenHashTable hash_table = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_DATA, INTERNAL_MEM_BRIDGE_DATA, sizeof (HashEntry), mono_aligned_addr_hash, NULL);
+static SgenHashTable hash_table = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_HASH_TABLE, INTERNAL_MEM_BRIDGE_HASH_TABLE_ENTRY, sizeof (HashEntry), mono_aligned_addr_hash, NULL);
 
 static MonoGCBridgeCallbacks bridge_callbacks;
 
 static int current_time;
 
+gboolean bridge_processing_in_progress = FALSE;
+
+void
+mono_gc_wait_for_bridge_processing (void)
+{
+       if (!bridge_processing_in_progress)
+               return;
+
+       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "GC_BRIDGE waiting for bridge processing to finish");
+
+       sgen_gc_lock ();
+       sgen_gc_unlock ();
+}
+
 void
 mono_gc_register_bridge_callbacks (MonoGCBridgeCallbacks *callbacks)
 {
@@ -539,6 +554,13 @@ sgen_bridge_processing_stw_step (void)
        if (!registered_bridges.size)
                return;
 
+       /*
+        * bridge_processing_in_progress must be set with the world
+        * stopped.  If not there would be race conditions.
+        */
+       g_assert (!bridge_processing_in_progress);
+       bridge_processing_in_progress = TRUE;
+
        SGEN_TV_GETTIME (btv);
 
        /* first DFS pass */
@@ -547,15 +569,37 @@ sgen_bridge_processing_stw_step (void)
        dyn_array_int_init (&merge_array);
 
        current_time = 0;
+       /*
+       First we insert all bridges into the hash table and then we do dfs1.
+
+       It must be done in 2 steps since the bridge arrays doesn't come in reverse topological order,
+       which means that we can have entry N pointing to entry N + 1.
+
+       If we dfs1 entry N before N + 1 is registered we'll not consider N + 1 for this bridge
+       pass and not create the required xref between the two.
+       */
        for (i = 0; i < registered_bridges.size; ++i)
-               dfs1 (register_bridge_object (DYN_ARRAY_PTR_REF (&registered_bridges, i)), NULL);
+               register_bridge_object (DYN_ARRAY_PTR_REF (&registered_bridges, i));
+
+       for (i = 0; i < registered_bridges.size; ++i)
+               dfs1 (get_hash_entry (DYN_ARRAY_PTR_REF (&registered_bridges, i), NULL), NULL);
 
        SGEN_TV_GETTIME (atv);
        step_2 = SGEN_TV_ELAPSED (btv, atv);
 }
 
+static mono_bool
+is_bridge_object_alive (MonoObject *obj, void *data)
+{
+       SgenHashTable *table = data;
+       unsigned char *value = sgen_hash_table_lookup (table, obj);
+       if (!value)
+               return TRUE;
+       return *value;
+}
+
 void
-sgen_bridge_processing_finish (void)
+sgen_bridge_processing_finish (int generation)
 {
        int i, j;
        int num_sccs, num_xrefs;
@@ -567,17 +611,20 @@ sgen_bridge_processing_finish (void)
        HashEntry **all_entries;
        MonoGCBridgeSCC **api_sccs;
        MonoGCBridgeXRef *api_xrefs;
+       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);
        SGEN_TV_DECLARE (atv);
        SGEN_TV_DECLARE (btv);
 
        if (!registered_bridges.size)
                return;
 
+       g_assert (bridge_processing_in_progress);
+
        SGEN_TV_GETTIME (atv);
 
        /* alloc and fill array of all entries */
 
-       all_entries = sgen_alloc_internal_dynamic (sizeof (HashEntry*) * hash_table.num_entries, INTERNAL_MEM_BRIDGE_DATA);
+       all_entries = sgen_alloc_internal_dynamic (sizeof (HashEntry*) * hash_table.num_entries, INTERNAL_MEM_BRIDGE_DATA, TRUE);
 
        j = 0;
        SGEN_HASH_TABLE_FOREACH (&hash_table, obj, entry) {
@@ -638,7 +685,7 @@ sgen_bridge_processing_finish (void)
                max_sccs_links = MAX (max_sccs_links, scc->xrefs.size);
        }
 
-       api_sccs = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC*) * num_sccs, INTERNAL_MEM_BRIDGE_DATA);
+       api_sccs = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC*) * num_sccs, INTERNAL_MEM_BRIDGE_DATA, TRUE);
        num_xrefs = 0;
        j = 0;
        for (i = 0; i < sccs.size; ++i) {
@@ -646,7 +693,8 @@ sgen_bridge_processing_finish (void)
                if (!scc->num_bridge_entries)
                        continue;
 
-               api_sccs [j] = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC) + sizeof (MonoObject*) * scc->num_bridge_entries, INTERNAL_MEM_BRIDGE_DATA);
+               api_sccs [j] = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC) + sizeof (MonoObject*) * scc->num_bridge_entries, INTERNAL_MEM_BRIDGE_DATA, TRUE);
+               api_sccs [j]->is_alive = FALSE;
                api_sccs [j]->num_objs = scc->num_bridge_entries;
                scc->num_bridge_entries = 0;
                scc->api_index = j++;
@@ -661,7 +709,7 @@ sgen_bridge_processing_finish (void)
                }
        } SGEN_HASH_TABLE_FOREACH_END;
 
-       api_xrefs = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeXRef) * num_xrefs, INTERNAL_MEM_BRIDGE_DATA);
+       api_xrefs = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeXRef) * num_xrefs, INTERNAL_MEM_BRIDGE_DATA, TRUE);
        j = 0;
        for (i = 0; i < sccs.size; ++i) {
                int k;
@@ -714,17 +762,29 @@ sgen_bridge_processing_finish (void)
 
        bridge_callbacks.cross_references (num_sccs, api_sccs, num_xrefs, api_xrefs);
 
-/*Release for finalization those objects we no longer care. */
+       /* Release for finalization those objects we no longer care. */
        SGEN_TV_GETTIME (btv);
        step_7 = SGEN_TV_ELAPSED (atv, btv);
 
        for (i = 0; i < num_sccs; ++i) {
-               if (!api_sccs [i]->objs [0])
-                       continue;
-               for (j = 0; j < api_sccs [i]->num_objs; ++j)
-                       sgen_mark_bridge_object (api_sccs [i]->objs [j]);
+               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_with_predicate (GENERATION_NURSERY, is_bridge_object_alive, &alive_hash);
+       if (generation == GENERATION_OLD)
+               sgen_null_links_with_predicate (GENERATION_OLD, is_bridge_object_alive, &alive_hash);
+
+       sgen_hash_table_clean (&alive_hash);
+
        /* free callback data */
 
        for (i = 0; i < num_sccs; ++i) {
@@ -753,6 +813,8 @@ sgen_bridge_processing_finish (void)
                dsf1_passes, dsf2_passes);
 
        step_1 = 0; /* We must cleanup since this value is used as an accumulator. */
+
+       bridge_processing_in_progress = FALSE;
 }
 
 static const char *bridge_class;