Merge pull request #2815 from lambdageek/dev/monoerror-mono_compile_method
[mono.git] / mono / metadata / sgen-new-bridge.c
index 990a7ecdcb4bd9901ef6454aa9e97c183d434279..a1eb82a714fcdbfa72a89003e1eb988869f8a0b9 100644 (file)
@@ -3,38 +3,10 @@
  *
  * Copyright 2011 Novell, Inc (http://www.novell.com)
  * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose,  provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- *
- *
  * Copyright 2001-2003 Ximian, Inc
  * Copyright 2003-2010 Novell, Inc.
  *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
 #include "config.h"
 #include <stdlib.h>
 #include <errno.h>
 
-#include "sgen-gc.h"
-#include "sgen-bridge.h"
-#include "sgen-hash-table.h"
-#include "sgen-qsort.h"
+#include "sgen/sgen-gc.h"
+#include "sgen-bridge-internals.h"
+#include "sgen/sgen-hash-table.h"
+#include "sgen/sgen-qsort.h"
+#include "sgen/sgen-client.h"
 #include "tabledefs.h"
-#include "utils/mono-logger-internal.h"
-#include "utils/mono-time.h"
-#include "utils/mono-compiler.h"
+#include "utils/mono-logger-internals.h"
 
 //#define NEW_XREFS
 #ifdef NEW_XREFS
 #define XREFS old_xrefs
 #endif
 
+#define OPTIMIZATION_COPY
+#define OPTIMIZATION_FORWARD
+#define OPTIMIZATION_SINGLETON_DYN_ARRAY
+
 typedef struct {
        int size;
        int capacity;           /* if negative, data points to another DynArray's data */
@@ -90,24 +65,30 @@ typedef struct {
 
 
 /*
+ * Bridge data for a single managed object
+ *
  * FIXME: Optimizations:
  *
- * Don't allocate a scrs array for just one source.  Most objects have
+ * Don't allocate a srcs array for just one source.  Most objects have
  * just one source, so use the srcs pointer itself.
  */
 typedef struct _HashEntry {
-       MonoObject *obj;        /* This is a duplicate - it's already stored in the hash table */
-
        gboolean is_bridge;
-       gboolean is_visited;
-
-       int finishing_time;
-
-       struct _HashEntry *forwarded_to;
 
+       union {
+               struct {
+                       guint32 is_visited : 1;
+                       guint32 finishing_time : 31;
+                       struct _HashEntry *forwarded_to;
+               } dfs1;
+               struct {
+                       // Index in sccs array of SCC this object was folded into
+                       int scc_index;
+               } dfs2;
+       } v;
+
+       // "Source" managed objects pointing at this destination
        DynPtrArray srcs;
-
-       int scc_index;
 } HashEntry;
 
 typedef struct {
@@ -115,12 +96,19 @@ typedef struct {
        double weight;
 } HashEntryWithAccounting;
 
+// The graph of managed objects/HashEntries is reduced to a graph of strongly connected components
 typedef struct _SCC {
        int index;
        int api_index;
+
+       // How many bridged objects does this SCC hold references to?
        int num_bridge_entries;
+
        gboolean flag;
+
        /*
+        * Index in global sccs array of SCCs holding pointers to this SCC
+        *
         * New and old xrefs are typically mutually exclusive.  Only when TEST_NEW_XREFS is
         * enabled we do both, and compare the results.  This should only be done for
         * debugging, obviously.
@@ -133,12 +121,14 @@ typedef struct _SCC {
 #endif
 } SCC;
 
+// Maps managed objects to corresponding HashEntry stricts
 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 int current_time;
+static guint32 current_time;
 
 static gboolean bridge_accounting_enabled = FALSE;
 
+static SgenBridgeProcessor *bridge_processor;
 
 /* Core functions */
 /* public */
@@ -193,7 +183,7 @@ dyn_array_ensure_capacity (DynArray *da, int capacity, int elem_size)
        while (capacity > da->capacity)
                da->capacity *= 2;
 
-       new_data = sgen_alloc_internal_dynamic (elem_size * da->capacity, INTERNAL_MEM_BRIDGE_DATA, TRUE);
+       new_data = (char *)sgen_alloc_internal_dynamic (elem_size * da->capacity, INTERNAL_MEM_BRIDGE_DATA, TRUE);
        memcpy (new_data, da->data, elem_size * da->size);
        if (old_capacity > 0)
                sgen_free_internal_dynamic (da->data, elem_size * old_capacity, INTERNAL_MEM_BRIDGE_DATA);
@@ -259,16 +249,18 @@ dyn_array_int_size (DynIntArray *da)
        return da->array.size;
 }
 
+#ifdef NEW_XREFS
 static void
 dyn_array_int_empty (DynIntArray *da)
 {
        dyn_array_empty (&da->array);
 }
+#endif
 
 static void
 dyn_array_int_add (DynIntArray *da, int x)
 {
-       int *p = dyn_array_add (&da->array, sizeof (int));
+       int *p = (int *)dyn_array_add (&da->array, sizeof (int));
        *p = x;
 }
 
@@ -278,17 +270,13 @@ dyn_array_int_get (DynIntArray *da, int x)
        return ((int*)da->array.data)[x];
 }
 
+#ifdef NEW_XREFS
 static void
 dyn_array_int_set (DynIntArray *da, int idx, int val)
 {
        ((int*)da->array.data)[idx] = val;
 }
-
-static void
-dyn_array_int_ensure_capacity (DynIntArray *da, int capacity)
-{
-       dyn_array_ensure_capacity (&da->array, capacity, sizeof (int));
-}
+#endif
 
 static void
 dyn_array_int_ensure_independent (DynIntArray *da)
@@ -319,7 +307,12 @@ dyn_array_ptr_init (DynPtrArray *da)
 static void
 dyn_array_ptr_uninit (DynPtrArray *da)
 {
-       dyn_array_uninit (&da->array, sizeof (void*));
+#ifdef OPTIMIZATION_SINGLETON_DYN_ARRAY
+       if (da->array.capacity == 1)
+               dyn_array_ptr_init (da);
+       else
+#endif
+               dyn_array_uninit (&da->array, sizeof (void*));
 }
 
 static int
@@ -331,19 +324,48 @@ dyn_array_ptr_size (DynPtrArray *da)
 static void
 dyn_array_ptr_empty (DynPtrArray *da)
 {
-       dyn_array_empty (&da->array);
+#ifdef OPTIMIZATION_SINGLETON_DYN_ARRAY
+       if (da->array.capacity == 1)
+               dyn_array_ptr_init (da);
+       else
+#endif
+               dyn_array_empty (&da->array);
 }
 
 static void*
 dyn_array_ptr_get (DynPtrArray *da, int x)
 {
+#ifdef OPTIMIZATION_SINGLETON_DYN_ARRAY
+       if (da->array.capacity == 1) {
+               g_assert (x == 0);
+               return da->array.data;
+       }
+#endif
        return ((void**)da->array.data)[x];
 }
 
 static void
 dyn_array_ptr_add (DynPtrArray *da, void *ptr)
 {
-       void **p = dyn_array_add (&da->array, sizeof (void*));
+       void **p;
+
+#ifdef OPTIMIZATION_SINGLETON_DYN_ARRAY
+       if (da->array.capacity == 0) {
+               da->array.capacity = 1;
+               da->array.size = 1;
+               p = (void**)&da->array.data;
+       } else if (da->array.capacity == 1) {
+               void *ptr0 = da->array.data;
+               void **p0;
+               dyn_array_init (&da->array);
+               p0 = (void **)dyn_array_add (&da->array, sizeof (void*));
+               *p0 = ptr0;
+               p = (void **)dyn_array_add (&da->array, sizeof (void*));
+       } else
+#endif
+       {
+               p = (void **)dyn_array_add (&da->array, sizeof (void*));
+       }
        *p = ptr;
 }
 
@@ -352,12 +374,21 @@ dyn_array_ptr_add (DynPtrArray *da, void *ptr)
 static void*
 dyn_array_ptr_pop (DynPtrArray *da)
 {
-       void *p;
        int size = da->array.size;
+       void *p;
        g_assert (size > 0);
-       dyn_array_ensure_independent (&da->array, sizeof (void*));
-       p = dyn_array_ptr_get (da, size - 1);
-       --da->array.size;
+#ifdef OPTIMIZATION_SINGLETON_DYN_ARRAY
+       if (da->array.capacity == 1) {
+               p = dyn_array_ptr_get (da, 0);
+               dyn_array_init (&da->array);
+       } else
+#endif
+       {
+               g_assert (da->array.capacity > 1);
+               dyn_array_ensure_independent (&da->array, sizeof (void*));
+               p = dyn_array_ptr_get (da, size - 1);
+               --da->array.size;
+       }
        return p;
 }
 
@@ -384,7 +415,7 @@ dyn_array_scc_size (DynSCCArray *da)
 static SCC*
 dyn_array_scc_add (DynSCCArray *da)
 {
-       return dyn_array_add (&da->array, sizeof (SCC));
+       return (SCC *)dyn_array_add (&da->array, sizeof (SCC));
 }
 
 static SCC*
@@ -397,6 +428,7 @@ dyn_array_scc_get_ptr (DynSCCArray *da, int x)
 
 static DynIntArray merge_array;
 
+#ifdef NEW_XREFS
 static gboolean
 dyn_array_int_contains (DynIntArray *da, int x)
 {
@@ -406,37 +438,39 @@ dyn_array_int_contains (DynIntArray *da, int x)
                        return TRUE;
        return FALSE;
 }
+#endif
 
 static void
 enable_accounting (void)
 {
+       SgenHashTable table = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_HASH_TABLE, INTERNAL_MEM_BRIDGE_HASH_TABLE_ENTRY, sizeof (HashEntryWithAccounting), mono_aligned_addr_hash, NULL);
        bridge_accounting_enabled = TRUE;
-       hash_table = (SgenHashTable)SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_HASH_TABLE, INTERNAL_MEM_BRIDGE_HASH_TABLE_ENTRY, sizeof (HashEntryWithAccounting), mono_aligned_addr_hash, NULL);
+       hash_table = table;
 }
 
 static MonoGCBridgeObjectKind
-class_kind (MonoClass *class)
+class_kind (MonoClass *klass)
 {
-       MonoGCBridgeObjectKind res = bridge_callbacks.bridge_class_kind (class);
+       MonoGCBridgeObjectKind res = bridge_callbacks.bridge_class_kind (klass);
 
        /* If it's a bridge, nothing we can do about it. */
        if (res == GC_BRIDGE_TRANSPARENT_BRIDGE_CLASS || res == GC_BRIDGE_OPAQUE_BRIDGE_CLASS)
                return res;
 
        /* Non bridge classes with no pointers will never point to a bridge, so we can savely ignore them. */
-       if (!class->has_references) {
-               SGEN_LOG (6, "class %s is opaque\n", class->name);
+       if (!klass->has_references) {
+               SGEN_LOG (6, "class %s is opaque\n", klass->name);
                return GC_BRIDGE_OPAQUE_CLASS;
        }
 
        /* Some arrays can be ignored */
-       if (class->rank == 1) {
-               MonoClass *elem_class = class->element_class;
+       if (klass->rank == 1) {
+               MonoClass *elem_class = klass->element_class;
 
                /* FIXME the bridge check can be quite expensive, cache it at the class level. */
                /* An array of a sealed type that is not a bridge will never get to a bridge */
                if ((elem_class->flags & TYPE_ATTRIBUTE_SEALED) && !elem_class->has_references && !bridge_callbacks.bridge_class_kind (elem_class)) {
-                       SGEN_LOG (6, "class %s is opaque\n", class->name);
+                       SGEN_LOG (6, "class %s is opaque\n", klass->name);
                        return GC_BRIDGE_OPAQUE_CLASS;
                }
        }
@@ -447,7 +481,7 @@ class_kind (MonoClass *class)
 static HashEntry*
 get_hash_entry (MonoObject *obj, gboolean *existing)
 {
-       HashEntry *entry = sgen_hash_table_lookup (&hash_table, obj);
+       HashEntry *entry = (HashEntry *)sgen_hash_table_lookup (&hash_table, obj);
        HashEntry new_entry;
 
        if (entry) {
@@ -460,14 +494,12 @@ get_hash_entry (MonoObject *obj, gboolean *existing)
 
        memset (&new_entry, 0, sizeof (HashEntry));
 
-       new_entry.obj = obj;
        dyn_array_ptr_init (&new_entry.srcs);
-       new_entry.finishing_time = -1;
-       new_entry.scc_index = -1;
+       new_entry.v.dfs1.finishing_time = 0;
 
        sgen_hash_table_replace (&hash_table, obj, &new_entry, NULL);
 
-       return sgen_hash_table_lookup (&hash_table, obj);
+       return (HashEntry *)sgen_hash_table_lookup (&hash_table, obj);
 }
 
 static void
@@ -479,12 +511,12 @@ add_source (HashEntry *entry, HashEntry *src)
 static void
 free_data (void)
 {
-       MonoObject *obj;
+       MonoObject *obj G_GNUC_UNUSED;
        HashEntry *entry;
        int total_srcs = 0;
        int max_srcs = 0;
 
-       SGEN_HASH_TABLE_FOREACH (&hash_table, obj, entry) {
+       SGEN_HASH_TABLE_FOREACH (&hash_table, MonoObject *, obj, HashEntry *, entry) {
                int entry_size = dyn_array_ptr_size (&entry->srcs);
                total_srcs += entry_size;
                if (entry_size > max_srcs)
@@ -507,10 +539,12 @@ register_bridge_object (MonoObject *obj)
 }
 
 static void
-register_finishing_time (HashEntry *entry, int t)
+register_finishing_time (HashEntry *entry, guint32 t)
 {
-       g_assert (entry->finishing_time < 0);
-       entry->finishing_time = t;
+       g_assert (entry->v.dfs1.finishing_time == 0);
+       /* finishing_time has 31 bits, so it must be within signed int32 range. */
+       g_assert (t > 0 && t <= G_MAXINT32);
+       entry->v.dfs1.finishing_time = t;
 }
 
 static int ignored_objects;
@@ -547,8 +581,16 @@ object_needs_expansion (MonoObject **objp)
 static HashEntry*
 follow_forward (HashEntry *entry)
 {
-       while (entry->forwarded_to)
-               entry = entry->forwarded_to;
+#ifdef OPTIMIZATION_FORWARD
+       while (entry->v.dfs1.forwarded_to) {
+               HashEntry *next = entry->v.dfs1.forwarded_to;
+               if (next->v.dfs1.forwarded_to)
+                       entry->v.dfs1.forwarded_to = next->v.dfs1.forwarded_to;
+               entry = next;
+       }
+#else
+       g_assert (!entry->v.dfs1.forwarded_to);
+#endif
        return entry;
 }
 
@@ -567,7 +609,7 @@ static int dfs1_passes, dfs2_passes;
 
 #undef HANDLE_PTR
 #define HANDLE_PTR(ptr,obj)    do {                                    \
-               MonoObject *dst = (MonoObject*)*(ptr);                  \
+               GCObject *dst = (GCObject*)*(ptr);                      \
                if (dst && object_needs_expansion (&dst)) {                     \
                        ++num_links;                                    \
                        dyn_array_ptr_push (&dfs_stack, obj_entry);     \
@@ -589,30 +631,32 @@ dfs1 (HashEntry *obj_entry)
                char *start;
                ++dfs1_passes;
 
-               obj_entry = dyn_array_ptr_pop (&dfs_stack);
+               obj_entry = (HashEntry *)dyn_array_ptr_pop (&dfs_stack);
                if (obj_entry) {
                        /* obj_entry needs to be expanded */
-                       src = dyn_array_ptr_pop (&dfs_stack);
+                       src = (HashEntry *)dyn_array_ptr_pop (&dfs_stack);
+
                        if (src)
-                               g_assert (!src->forwarded_to);
+                               g_assert (!src->v.dfs1.forwarded_to);
 
                        obj_entry = follow_forward (obj_entry);
 
                again:
-                       g_assert (!obj_entry->forwarded_to);
-                       obj = obj_entry->obj;
+                       g_assert (!obj_entry->v.dfs1.forwarded_to);
+                       obj = sgen_hash_table_key_for_value_pointer (obj_entry);
                        start = (char*)obj;
 
-                       if (!obj_entry->is_visited) {
+                       if (!obj_entry->v.dfs1.is_visited) {
                                int num_links = 0;
+                               mword desc = sgen_obj_get_descriptor_safe (obj);
 
-                               obj_entry->is_visited = TRUE;
+                               obj_entry->v.dfs1.is_visited = 1;
 
                                /* push the finishing entry on the stack */
                                dyn_array_ptr_push (&dfs_stack, obj_entry);
                                dyn_array_ptr_push (&dfs_stack, NULL);
 
-#include "sgen-scan-object.h"
+#include "sgen/sgen-scan-object.h"
 
                                /*
                                 * We can remove non-bridge objects with a single outgoing
@@ -624,20 +668,24 @@ dfs1 (HashEntry *obj_entry)
                                 * continuing processing this object, we start over with the
                                 * object it points to.
                                 */
+#ifdef OPTIMIZATION_FORWARD
                                if (!obj_entry->is_bridge && num_links == 1) {
-                                       HashEntry *dst_entry = dyn_array_ptr_pop (&dfs_stack);
-                                       HashEntry *obj_entry_again = dyn_array_ptr_pop (&dfs_stack);
+                                       HashEntry *dst_entry = (HashEntry *)dyn_array_ptr_pop (&dfs_stack);
+                                       HashEntry *obj_entry_again = (HashEntry *)dyn_array_ptr_pop (&dfs_stack);
                                        g_assert (obj_entry_again == obj_entry);
-                                       g_assert (!dst_entry->forwarded_to);
-                                       obj_entry->forwarded_to = dst_entry;
-                                       obj_entry = dst_entry;
+                                       g_assert (!dst_entry->v.dfs1.forwarded_to);
+                                       if (obj_entry != dst_entry) {
+                                               obj_entry->v.dfs1.forwarded_to = dst_entry;
+                                               obj_entry = dst_entry;
+                                       }
                                        goto again;
                                }
+#endif
                        }
 
                        if (src) {
                                //g_print ("link %s -> %s\n", sgen_safe_name (src->obj), sgen_safe_name (obj));
-                               g_assert (!obj_entry->forwarded_to);
+                               g_assert (!obj_entry->v.dfs1.forwarded_to);
                                add_source (obj_entry, src);
                        } else {
                                //g_print ("starting with %s\n", sgen_safe_name (obj));
@@ -645,10 +693,10 @@ dfs1 (HashEntry *obj_entry)
                } else {
                        /* obj_entry needs to be finished */
 
-                       obj_entry = dyn_array_ptr_pop (&dfs_stack);
+                       obj_entry = (HashEntry *)dyn_array_ptr_pop (&dfs_stack);
 
                        //g_print ("finish %s\n", sgen_safe_name (obj_entry->obj));
-                       register_finishing_time (obj_entry, current_time++);
+                       register_finishing_time (obj_entry, ++current_time);
                }
        } while (dyn_array_ptr_size (&dfs_stack) > 0);
 }
@@ -736,8 +784,10 @@ scc_add_xref (SCC *src, SCC *dst)
                        return;
                src->flag = TRUE;
                dyn_array_int_add (&dst->old_xrefs, src->index);
+#ifdef OPTIMIZATION_COPY
        } else if (dyn_array_int_size (&dst->old_xrefs) == 0) {
                dyn_array_int_copy (&dst->old_xrefs, &src->old_xrefs);
+#endif
        } else {
                int i;
                for (i = 0; i < dyn_array_int_size (&src->old_xrefs); ++i) {
@@ -756,8 +806,8 @@ scc_add_xref (SCC *src, SCC *dst)
 static void
 scc_add_entry (SCC *scc, HashEntry *entry)
 {
-       g_assert (entry->scc_index < 0);
-       entry->scc_index = scc->index;
+       g_assert (entry->v.dfs2.scc_index < 0);
+       entry->v.dfs2.scc_index = scc->index;
        if (entry->is_bridge)
                ++scc->num_bridge_entries;
 }
@@ -772,12 +822,12 @@ dfs2 (HashEntry *entry)
        dyn_array_ptr_push (&dfs_stack, entry);
 
        do {
-               entry = dyn_array_ptr_pop (&dfs_stack);
+               entry = (HashEntry *)dyn_array_ptr_pop (&dfs_stack);
                ++dfs2_passes;
 
-               if (entry->scc_index >= 0) {
-                       if (entry->scc_index != current_scc->index)
-                               scc_add_xref (dyn_array_scc_get_ptr (&sccs, entry->scc_index), current_scc);
+               if (entry->v.dfs2.scc_index >= 0) {
+                       if (entry->v.dfs2.scc_index != current_scc->index)
+                               scc_add_xref (dyn_array_scc_get_ptr (&sccs, entry->v.dfs2.scc_index), current_scc);
                        continue;
                }
 
@@ -843,8 +893,8 @@ dump_graph (void)
 
        MonoObject *obj;
        HashEntry *entry;
-       int prefix_len = strlen (dump_prefix);
-       char filename [prefix_len + 64];
+       size_t prefix_len = strlen (dump_prefix);
+       char *filename = (char *)alloca (prefix_len + 64);
        FILE *file;
        int edge_id = 0;
 
@@ -865,19 +915,19 @@ dump_graph (void)
                        "</attributes>\n");
 
        fprintf (file, "<nodes>\n");
-       SGEN_HASH_TABLE_FOREACH (&hash_table, obj, entry) {
-               MonoVTable *vt = (MonoVTable*) SGEN_LOAD_VTABLE (obj);
+       SGEN_HASH_TABLE_FOREACH (&hash_table, MonoObject *, obj, HashEntry *, entry) {
+               MonoVTable *vt = SGEN_LOAD_VTABLE (obj);
                fprintf (file, "<node id=\"%p\"><attvalues><attvalue for=\"0\" value=\"%s.%s\"/><attvalue for=\"1\" value=\"%s\"/></attvalues></node>\n",
                                obj, vt->klass->name_space, vt->klass->name, entry->is_bridge ? "true" : "false");
        } SGEN_HASH_TABLE_FOREACH_END;
        fprintf (file, "</nodes>\n");
 
        fprintf (file, "<edges>\n");
-       SGEN_HASH_TABLE_FOREACH (&hash_table, obj, entry) {
+       SGEN_HASH_TABLE_FOREACH (&hash_table, MonoObject *, obj, HashEntry *, entry) {
                int i;
                for (i = 0; i < dyn_array_ptr_size (&entry->srcs); ++i) {
-                       HashEntry *src = dyn_array_ptr_get (&entry->srcs, i);
-                       fprintf (file, "<edge id=\"%d\" source=\"%p\" target=\"%p\"/>\n", edge_id++, src->obj, obj);
+                       HashEntry *src = (HashEntry *)dyn_array_ptr_get (&entry->srcs, i);
+                       fprintf (file, "<edge id=\"%d\" source=\"%p\" target=\"%p\"/>\n", edge_id++, sgen_hash_table_key_for_value_pointer (src), obj);
                }
        } SGEN_HASH_TABLE_FOREACH_END;
        fprintf (file, "</edges>\n");
@@ -896,17 +946,18 @@ set_dump_prefix (const char *prefix)
 static int
 compare_hash_entries (const HashEntry *e1, const HashEntry *e2)
 {
-       return e2->finishing_time - e1->finishing_time;
+       /* We can cast to signed int here because finishing_time has only 31 bits. */
+       return (gint32)e2->v.dfs1.finishing_time - (gint32)e1->v.dfs1.finishing_time;
 }
 
 DEF_QSORT_INLINE(hash_entries, HashEntry*, compare_hash_entries)
 
-static unsigned long step_1, step_2, step_3, step_4, step_5, step_6, step_7, step_8;
+static gint64 step_1, step_2, step_3, step_4, step_5, step_6;
 static int fist_pass_links, second_pass_links, sccs_links;
 static int max_sccs_links = 0;
 
 static void
-register_finalized_object (MonoObject *obj)
+register_finalized_object (GCObject *obj)
 {
        g_assert (sgen_need_bridge_processing ());
        dyn_array_ptr_push (&registered_bridges, obj);
@@ -923,7 +974,7 @@ processing_stw_step (void)
 {
        int i;
        int bridge_count;
-       MonoObject *obj;
+       MonoObject *obj G_GNUC_UNUSED;
        HashEntry *entry;
        SGEN_TV_DECLARE (atv);
        SGEN_TV_DECLARE (btv);
@@ -931,12 +982,6 @@ processing_stw_step (void)
        if (!dyn_array_ptr_size (&registered_bridges))
                return;
 
-       /*
-        * bridge_processing_in_progress must be set with the world
-        * stopped.  If not there would be race conditions.
-        */
-       bridge_processing_in_progress = TRUE;
-
        SGEN_TV_GETTIME (btv);
 
        /* first DFS pass */
@@ -956,14 +1001,14 @@ processing_stw_step (void)
        */
        bridge_count = dyn_array_ptr_size (&registered_bridges);
        for (i = 0; i < bridge_count ; ++i)
-               register_bridge_object (dyn_array_ptr_get (&registered_bridges, i));
+               register_bridge_object ((MonoObject *)dyn_array_ptr_get (&registered_bridges, i));
 
        for (i = 0; i < bridge_count; ++i)
-               dfs1 (get_hash_entry (dyn_array_ptr_get (&registered_bridges, i), NULL));
+               dfs1 (get_hash_entry ((MonoObject *)dyn_array_ptr_get (&registered_bridges, i), NULL));
 
        /* Remove all forwarded objects. */
-       SGEN_HASH_TABLE_FOREACH (&hash_table, obj, entry) {
-               if (entry->forwarded_to) {
+       SGEN_HASH_TABLE_FOREACH (&hash_table, MonoObject *, obj, HashEntry *, entry) {
+               if (entry->v.dfs1.forwarded_to) {
                        g_assert (dyn_array_ptr_size (&entry->srcs) == 0);
                        SGEN_HASH_TABLE_FOREACH_REMOVE (TRUE);
                        continue;
@@ -977,33 +1022,25 @@ processing_stw_step (void)
                dump_graph ();
 }
 
-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;
-}
+static int num_registered_bridges, hash_table_size;
 
 static void
-processing_finish (int generation)
+processing_build_callback_data (int generation)
 {
        int i, j;
        int num_sccs, num_xrefs;
        int max_entries, max_xrefs;
-       int hash_table_size, sccs_size;
-       MonoObject *obj;
+       MonoObject *obj G_GNUC_UNUSED;
        HashEntry *entry;
-       int num_registered_bridges;
        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);
 
+       g_assert (bridge_processor->num_sccs == 0 && bridge_processor->num_xrefs == 0);
+       g_assert (!bridge_processor->api_sccs && !bridge_processor->api_xrefs);
+
        if (!dyn_array_ptr_size (&registered_bridges))
                return;
 
@@ -1013,11 +1050,11 @@ processing_finish (int generation)
 
        /* alloc and fill array of all entries */
 
-       all_entries = sgen_alloc_internal_dynamic (sizeof (HashEntry*) * hash_table.num_entries, INTERNAL_MEM_BRIDGE_DATA, TRUE);
+       all_entries = (HashEntry **)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) {
-               g_assert (entry->finishing_time >= 0);
+       SGEN_HASH_TABLE_FOREACH (&hash_table, MonoObject *, obj, HashEntry *, entry) {
+               g_assert (entry->v.dfs1.finishing_time > 0);
                all_entries [j++] = entry;
                fist_pass_links += dyn_array_ptr_size (&entry->srcs);
        } SGEN_HASH_TABLE_FOREACH_END;
@@ -1027,6 +1064,10 @@ processing_finish (int generation)
        /* sort array according to decreasing finishing time */
        qsort_hash_entries (all_entries, hash_table.num_entries);
 
+       SGEN_HASH_TABLE_FOREACH (&hash_table, MonoObject *, obj, HashEntry *, entry) {
+               entry->v.dfs2.scc_index = -1;
+       } SGEN_HASH_TABLE_FOREACH_END;
+
        SGEN_TV_GETTIME (btv);
        step_3 = SGEN_TV_ELAPSED (atv, btv);
 
@@ -1035,7 +1076,7 @@ processing_finish (int generation)
        dyn_array_scc_init (&sccs);
        for (i = 0; i < hash_table.num_entries; ++i) {
                HashEntry *entry = all_entries [i];
-               if (entry->scc_index < 0) {
+               if (entry->v.dfs2.scc_index < 0) {
                        int index = dyn_array_scc_size (&sccs);
                        current_scc = dyn_array_scc_add (&sccs);
                        current_scc->index = index;
@@ -1133,7 +1174,7 @@ processing_finish (int generation)
                        double w;
                        HashEntryWithAccounting *entry = (HashEntryWithAccounting*)all_entries [i];
 
-                       entry->weight += (double)sgen_safe_object_get_size (entry->entry.obj);
+                       entry->weight += (double)sgen_safe_object_get_size (sgen_hash_table_key_for_value_pointer (entry));
                        w = entry->weight / dyn_array_ptr_size (&entry->entry.srcs);
                        for (j = 0; j < dyn_array_ptr_size (&entry->entry.srcs); ++j) {
                                HashEntryWithAccounting *other = (HashEntryWithAccounting *)dyn_array_ptr_get (&entry->entry.srcs, j);
@@ -1143,14 +1184,13 @@ processing_finish (int generation)
                for (i = 0; i < hash_table.num_entries; ++i) {
                        HashEntryWithAccounting *entry = (HashEntryWithAccounting*)all_entries [i];
                        if (entry->entry.is_bridge) {
-                               MonoClass *klass = ((MonoVTable*)SGEN_LOAD_VTABLE (entry->entry.obj))->klass;
-                               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "OBJECT %s::%s (%p) weight %f", klass->name_space, klass->name, entry->entry.obj, entry->weight);
+                               MonoObject *obj = sgen_hash_table_key_for_value_pointer (entry);
+                               MonoClass *klass = SGEN_LOAD_VTABLE (obj)->klass;
+                               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "OBJECT %s::%s (%p) weight %f", klass->name_space, klass->name, obj, entry->weight);
                        }
                }
        }
 
-       sccs_size = dyn_array_scc_size (&sccs);
-
        for (i = 0; i < hash_table.num_entries; ++i) {
                HashEntry *entry = all_entries [i];
                second_pass_links += dyn_array_ptr_size (&entry->srcs);
@@ -1175,7 +1215,7 @@ processing_finish (int generation)
                max_sccs_links = MAX (max_sccs_links, dyn_array_int_size (&scc->XREFS));
        }
 
-       api_sccs = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC*) * num_sccs, INTERNAL_MEM_BRIDGE_DATA, TRUE);
+       api_sccs = (MonoGCBridgeSCC **)sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC*) * num_sccs, INTERNAL_MEM_BRIDGE_DATA, TRUE);
        num_xrefs = 0;
        j = 0;
        for (i = 0; i < dyn_array_scc_size (&sccs); ++i) {
@@ -1183,7 +1223,7 @@ processing_finish (int generation)
                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, TRUE);
+               api_sccs [j] = (MonoGCBridgeSCC *)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;
@@ -1192,14 +1232,14 @@ processing_finish (int generation)
                num_xrefs += dyn_array_int_size (&scc->XREFS);
        }
 
-       SGEN_HASH_TABLE_FOREACH (&hash_table, obj, entry) {
+       SGEN_HASH_TABLE_FOREACH (&hash_table, MonoObject *, obj, HashEntry *, entry) {
                if (entry->is_bridge) {
-                       SCC *scc = dyn_array_scc_get_ptr (&sccs, entry->scc_index);
-                       api_sccs [scc->api_index]->objs [scc->num_bridge_entries++] = entry->obj;
+                       SCC *scc = dyn_array_scc_get_ptr (&sccs, entry->v.dfs2.scc_index);
+                       api_sccs [scc->api_index]->objs [scc->num_bridge_entries++] = sgen_hash_table_key_for_value_pointer (entry);
                }
        } SGEN_HASH_TABLE_FOREACH_END;
 
-       api_xrefs = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeXRef) * num_xrefs, INTERNAL_MEM_BRIDGE_DATA, TRUE);
+       api_xrefs = (MonoGCBridgeXRef *)sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeXRef) * num_xrefs, INTERNAL_MEM_BRIDGE_DATA, TRUE);
        j = 0;
        for (i = 0; i < dyn_array_scc_size (&sccs); ++i) {
                int k;
@@ -1253,59 +1293,33 @@ processing_finish (int generation)
 
        //g_print ("%d sccs containing bridges - %d max bridge objects - %d max xrefs\n", j, max_entries, max_xrefs);
 
-       /* callback */
-
-       bridge_callbacks.cross_references (num_sccs, api_sccs, num_xrefs, api_xrefs);
-
-       /* 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) {
-               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);
+       bridge_processor->num_sccs = num_sccs;
+       bridge_processor->api_sccs = api_sccs;
+       bridge_processor->num_xrefs = num_xrefs;
+       bridge_processor->api_xrefs = api_xrefs;
+}
 
-       sgen_hash_table_clean (&alive_hash);
+static void
+processing_after_callback (int generation)
+{
+       int i, j;
+       int num_sccs = bridge_processor->num_sccs;
+       MonoGCBridgeSCC **api_sccs = bridge_processor->api_sccs;
 
        if (bridge_accounting_enabled) {
                for (i = 0; i < num_sccs; ++i) {
-                       for (j = 0; j < api_sccs [i]->num_objs; ++j)
+                       for (j = 0; j < api_sccs [i]->num_objs; ++j) {
+                               GCVTable vtable = SGEN_LOAD_VTABLE (api_sccs [i]->objs [j]);
                                mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC,
                                        "OBJECT %s (%p) SCC [%d] %s",
-                                               sgen_safe_name (api_sccs [i]->objs [j]), api_sccs [i]->objs [j],
+                                               sgen_client_vtable_get_namespace (vtable), sgen_client_vtable_get_name (vtable), api_sccs [i]->objs [j],
                                                i,
                                                api_sccs [i]->is_alive  ? "ALIVE" : "DEAD");
+                       }
                }
        }
 
-       /* free callback data */
-
-       for (i = 0; i < num_sccs; ++i) {
-               sgen_free_internal_dynamic (api_sccs [i],
-                               sizeof (MonoGCBridgeSCC) + sizeof (MonoObject*) * api_sccs [i]->num_objs,
-                               INTERNAL_MEM_BRIDGE_DATA);
-       }
-       sgen_free_internal_dynamic (api_sccs, sizeof (MonoGCBridgeSCC*) * num_sccs, INTERNAL_MEM_BRIDGE_DATA);
-
-       sgen_free_internal_dynamic (api_xrefs, sizeof (MonoGCBridgeXRef) * num_xrefs, INTERNAL_MEM_BRIDGE_DATA);
-
-       SGEN_TV_GETTIME (atv);
-       step_8 = SGEN_TV_ELAPSED (btv, atv);
-
-       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "GC_BRIDGE num-objects %d num_hash_entries %d sccs size %d init %.2fms df1 %.2fms sort %.2fms dfs2 %.2fms setup-cb %.2fms free-data %.2fms user-cb %.2fms clenanup %.2fms links %d/%d/%d/%d dfs passes %d/%d ignored %d",
+       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "GC_NEW_BRIDGE num-objects %d num_hash_entries %d sccs size %d init %.2fms df1 %.2fms sort %.2fms dfs2 %.2fms setup-cb %.2fms free-data %.2fms links %d/%d/%d/%d dfs passes %d/%d ignored %d",
                num_registered_bridges, hash_table_size, dyn_array_scc_size (&sccs),
                step_1 / 10000.0f,
                step_2 / 10000.0f,
@@ -1313,20 +1327,16 @@ processing_finish (int generation)
                step_4 / 10000.0f,
                step_5 / 10000.0f,
                step_6 / 10000.0f,
-               step_7 / 10000.0f,
-               step_8 / 10000.f,
                fist_pass_links, second_pass_links, sccs_links, max_sccs_links,
                dfs1_passes, dfs2_passes, ignored_objects);
 
        step_1 = 0; /* We must cleanup since this value is used as an accumulator. */
        fist_pass_links = second_pass_links = sccs_links = max_sccs_links = 0;
        dfs1_passes = dfs2_passes = ignored_objects = 0;
-
-       bridge_processing_in_progress = FALSE;
 }
 
 static void
-describe_pointer (MonoObject *obj)
+describe_pointer (GCObject *obj)
 {
        HashEntry *entry;
        int i;
@@ -1338,13 +1348,13 @@ describe_pointer (MonoObject *obj)
                }
        }
 
-       entry = sgen_hash_table_lookup (&hash_table, obj);
+       entry = (HashEntry *)sgen_hash_table_lookup (&hash_table, obj);
        if (!entry)
                return;
 
        printf ("Bridge hash table entry %p:\n", entry);
        printf ("  is bridge: %d\n", (int)entry->is_bridge);
-       printf ("  is visited: %d\n", (int)entry->is_visited);
+       printf ("  is visited: %d\n", (int)entry->v.dfs1.is_visited);
 }
 
 void
@@ -1352,12 +1362,15 @@ sgen_new_bridge_init (SgenBridgeProcessor *collector)
 {
        collector->reset_data = reset_data;
        collector->processing_stw_step = processing_stw_step;
-       collector->processing_finish = processing_finish;
+       collector->processing_build_callback_data = processing_build_callback_data;
+       collector->processing_after_callback = processing_after_callback;
        collector->class_kind = class_kind;
        collector->register_finalized_object = register_finalized_object;
        collector->describe_pointer = describe_pointer;
        collector->enable_accounting = enable_accounting;
        collector->set_dump_prefix = set_dump_prefix;
+
+       bridge_processor = collector;
 }
 
 #endif