[xbuild] Add new reserved properties $(MSBuildThisFile*).
[mono.git] / mono / metadata / sgen-gc.c
index 1e2271175fae95c9a71ac6bb14dcaac97ed2ed2f..b9191c2383e41118751820d772614e2e00978cc5 100644 (file)
 #include "metadata/threads.h"
 #include "metadata/sgen-gc.h"
 #include "metadata/sgen-cardtable.h"
+#include "metadata/sgen-protocol.h"
 #include "metadata/sgen-archdep.h"
+#include "metadata/sgen-bridge.h"
 #include "metadata/mono-gc.h"
 #include "metadata/method-builder.h"
 #include "metadata/profiler-private.h"
@@ -241,8 +243,8 @@ enum {
  */
 
 static int gc_initialized = 0;
-/* If set, do a minor collection before every allocation */
-static gboolean collect_before_allocs = FALSE;
+/* If set, do a minor collection before every allocation */
+static guint32 collect_before_allocs = 0;
 /* If set, do a heap consistency check before each minor collection */
 static gboolean consistency_check_at_minor_collection = FALSE;
 /* If set, check that there are no references to the domain left at domain unload */
@@ -250,7 +252,7 @@ static gboolean xdomain_checks = FALSE;
 /* If not null, dump the heap after each collection into this file */
 static FILE *heap_dump_file = NULL;
 /* If set, mark stacks conservatively, even if precise marking is possible */
-static gboolean conservative_stack_mark = TRUE;
+static gboolean conservative_stack_mark = FALSE;
 /* If set, do a plausibility check on the scan_starts before and after
    each collection */
 static gboolean do_scan_starts_check = FALSE;
@@ -297,6 +299,8 @@ static int stat_wbarrier_value_copy = 0;
 static int stat_wbarrier_object_copy = 0;
 #endif
 
+static long long stat_pinned_objects = 0;
+
 static long long time_minor_pre_collection_fragment_clear = 0;
 static long long time_minor_pinning = 0;
 static long long time_minor_scan_remsets = 0;
@@ -323,8 +327,8 @@ static long long time_major_fragment_creation = 0;
 
 #define DEBUG(level,a) do {if (G_UNLIKELY ((level) <= SGEN_MAX_DEBUG_LEVEL && (level) <= gc_debug_level)) a;} while (0)
 
-static int gc_debug_level = 0;
-static FILE* gc_debug_file;
+int gc_debug_level = 0;
+FILE* gc_debug_file;
 
 /*
 void
@@ -341,10 +345,10 @@ mono_gc_flush_info (void)
  */
 #define USER_CONFIG 1
 
-#define TV_DECLARE(name) gint64 name
-#define TV_GETTIME(tv) tv = mono_100ns_ticks ()
-#define TV_ELAPSED(start,end) (int)((end-start) / 10)
-#define TV_ELAPSED_MS(start,end) ((TV_ELAPSED((start),(end)) + 500) / 1000)
+#define TV_DECLARE SGEN_TV_DECLARE
+#define TV_GETTIME SGEN_TV_GETTIME
+#define TV_ELAPSED SGEN_TV_ELAPSED
+#define TV_ELAPSED_MS SGEN_TV_ELAPSED_MS
 
 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
 
@@ -455,6 +459,12 @@ safe_name (void* obj)
 
 #define safe_object_get_size   mono_sgen_safe_object_get_size
 
+const char*
+mono_sgen_safe_name (void* obj)
+{
+       return safe_name (obj);
+}
+
 /*
  * ######################################################################
  * ########  Global data.
@@ -514,10 +524,14 @@ static mword highest_heap_address = 0;
 
 static LOCK_DECLARE (interruption_mutex);
 static LOCK_DECLARE (global_remset_mutex);
+static LOCK_DECLARE (pin_queue_mutex);
 
 #define LOCK_GLOBAL_REMSET pthread_mutex_lock (&global_remset_mutex)
 #define UNLOCK_GLOBAL_REMSET pthread_mutex_unlock (&global_remset_mutex)
 
+#define LOCK_PIN_QUEUE pthread_mutex_lock (&pin_queue_mutex)
+#define UNLOCK_PIN_QUEUE pthread_mutex_unlock (&pin_queue_mutex)
+
 typedef struct _FinalizeEntry FinalizeEntry;
 struct _FinalizeEntry {
        FinalizeEntry *next;
@@ -603,6 +617,33 @@ static int roots_hash_size [ROOT_TYPE_NUM] = { 0, 0, 0 };
 static mword roots_size = 0; /* amount of memory in the root set */
 static int num_roots_entries [ROOT_TYPE_NUM] = { 0, 0, 0 };
 
+#define GC_ROOT_NUM 32
+typedef struct {
+       int count;
+       void *objects [GC_ROOT_NUM];
+       int root_types [GC_ROOT_NUM];
+       uintptr_t extra_info [GC_ROOT_NUM];
+} GCRootReport;
+
+static void
+notify_gc_roots (GCRootReport *report)
+{
+       if (!report->count)
+               return;
+       mono_profiler_gc_roots (report->count, report->objects, report->root_types, report->extra_info);
+       report->count = 0;
+}
+
+static void
+add_profile_gc_root (GCRootReport *report, void *object, int rtype, uintptr_t extra_info)
+{
+       if (report->count == GC_ROOT_NUM)
+               notify_gc_roots (report);
+       report->objects [report->count] = object;
+       report->root_types [report->count] = rtype;
+       report->extra_info [report->count++] = (uintptr_t)((MonoVTable*)LOAD_VTABLE (object))->klass;
+}
+
 /* 
  * The current allocation cursors
  * We allocate objects in the nursery.
@@ -707,11 +748,56 @@ static MonoVTable *array_fill_vtable;
 
 /*
  * ######################################################################
- * ########  Macros and function declarations.
+ * ########  Heap size accounting
  * ######################################################################
  */
+/*heap limits*/
+static mword max_heap_size = ((mword)0)- ((mword)1);
+static mword allocated_heap;
+
+/*Object was pinned during the current collection*/
+static mword objects_pinned;
+
+void
+mono_sgen_release_space (mword size, int space)
+{
+       allocated_heap -= size;
+}
+
+static size_t
+available_free_space (void)
+{
+       return max_heap_size - MIN (allocated_heap, max_heap_size);
+}
+
+gboolean
+mono_sgen_try_alloc_space (mword size, int space)
+{
+       if (available_free_space () < size)
+               return FALSE;
+
+       allocated_heap += size;
+       return TRUE;
+}
+
+static void
+init_heap_size_limits (glong max_heap)
+{
+       if (max_heap == 0)
+               return;
+
+       if (max_heap < nursery_size * 4) {
+               fprintf (stderr, "max-heap-size must be at least 4 times larger than nursery size.\n");
+               exit (1);
+       }
+       max_heap_size = max_heap - nursery_size;
+}
 
-#define ADDR_IN_HEAP_BOUNDARIES(addr) ((p) >= lowest_heap_address && (p) < highest_heap_address)
+/*
+ * ######################################################################
+ * ########  Macros and function declarations.
+ * ######################################################################
+ */
 
 inline static void*
 align_pointer (void *ptr)
@@ -734,11 +820,13 @@ static void scan_thread_data (void *start_nursery, void *end_nursery, gboolean p
 static void scan_from_remsets (void *start_nursery, void *end_nursery, GrayQueue *queue);
 static void scan_from_registered_roots (CopyOrMarkObjectFunc copy_func, char *addr_start, char *addr_end, int root_type, GrayQueue *queue);
 static void scan_finalizer_entries (CopyOrMarkObjectFunc copy_func, FinalizeEntry *list, GrayQueue *queue);
+static void report_finalizer_roots (void);
+static void report_registered_roots (void);
 static void find_pinning_ref_from_thread (char *obj, size_t size);
 static void update_current_thread_stack (void *start);
 static void finalize_in_range (CopyOrMarkObjectFunc copy_func, char *start, char *end, int generation, GrayQueue *queue);
 static void add_or_remove_disappearing_link (MonoObject *obj, void **link, gboolean track, int generation);
-static void null_link_in_range (CopyOrMarkObjectFunc copy_func, char *start, char *end, int generation, GrayQueue *queue);
+static void null_link_in_range (CopyOrMarkObjectFunc copy_func, char *start, char *end, int generation, gboolean before_finalization, GrayQueue *queue);
 static void null_links_for_domain (MonoDomain *domain, int generation);
 static gboolean search_fragment_for_size (size_t size);
 static int search_fragment_for_size_range (size_t desired_size, size_t minimum_size);
@@ -749,9 +837,9 @@ static void optimize_pin_queue (int start_slot);
 static void clear_remsets (void);
 static void clear_tlabs (void);
 static void sort_addresses (void **array, int size);
-static void drain_gray_stack (GrayQueue *queue);
+static gboolean drain_gray_stack (GrayQueue *queue, int max_objs);
 static void finish_gray_stack (char *start_addr, char *end_addr, int generation, GrayQueue *queue);
-static gboolean need_major_collection (void);
+static gboolean need_major_collection (mword space_needed);
 static void major_collection (const char *reason);
 
 static void mono_gc_register_disappearing_link (MonoObject *obj, void **link, gboolean track);
@@ -775,12 +863,10 @@ static void null_ephemerons_for_domain (MonoDomain *domain);
 
 SgenMajorCollector major_collector;
 
-#include "sgen-protocol.c"
 #include "sgen-pinning.c"
 #include "sgen-pinning-stats.c"
 #include "sgen-gray.c"
 #include "sgen-workers.c"
-#include "sgen-los.c"
 #include "sgen-cardtable.c"
 
 /* Root bitmap descriptors are simpler: the lower three bits describe the type
@@ -1109,22 +1195,36 @@ scan_object_for_xdomain_refs (char *start, mword size, void *data)
 static void
 scan_object_for_specific_ref (char *start, MonoObject *key)
 {
+       char *forwarded;
+
+       if ((forwarded = SGEN_OBJECT_IS_FORWARDED (start)))
+               start = forwarded;
+
        #include "sgen-scan-object.h"
 }
 
 void
-mono_sgen_scan_area_with_callback (char *start, char *end, IterateObjectCallbackFunc callback, void *data)
+mono_sgen_scan_area_with_callback (char *start, char *end, IterateObjectCallbackFunc callback, void *data, gboolean allow_flags)
 {
        while (start < end) {
                size_t size;
+               char *obj;
+
                if (!*(void**)start) {
                        start += sizeof (void*); /* should be ALLOC_ALIGN, really */
                        continue;
                }
 
-               size = ALIGN_UP (safe_object_get_size ((MonoObject*) start));
+               if (allow_flags) {
+                       if (!(obj = SGEN_OBJECT_IS_FORWARDED (start)))
+                               obj = start;
+               } else {
+                       obj = start;
+               }
+
+               size = ALIGN_UP (safe_object_get_size ((MonoObject*)obj));
 
-               callback (start, size, data);
+               callback (obj, size, data);
 
                start += size;
        }
@@ -1213,17 +1313,15 @@ scan_roots_for_specific_ref (MonoObject *key, int root_type)
 void
 mono_gc_scan_for_specific_ref (MonoObject *key)
 {
-       LOSObject *bigobj;
        RootRecord *root;
        int i;
 
        mono_sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data,
-                       (IterateObjectCallbackFunc)scan_object_for_specific_ref_callback, key);
+                       (IterateObjectCallbackFunc)scan_object_for_specific_ref_callback, key, TRUE);
 
        major_collector.iterate_objects (TRUE, TRUE, (IterateObjectCallbackFunc)scan_object_for_specific_ref_callback, key);
 
-       for (bigobj = los_object_list; bigobj; bigobj = bigobj->next)
-               scan_object_for_specific_ref (bigobj->data, key);
+       mono_sgen_los_iterate_objects ((IterateObjectCallbackFunc)scan_object_for_specific_ref_callback, key);
 
        scan_roots_for_specific_ref (key, ROOT_TYPE_NORMAL);
        scan_roots_for_specific_ref (key, ROOT_TYPE_WBARRIER);
@@ -1369,7 +1467,7 @@ check_for_xdomain_refs (void)
        LOSObject *bigobj;
 
        mono_sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data,
-                       (IterateObjectCallbackFunc)scan_object_for_xdomain_refs, NULL);
+                       (IterateObjectCallbackFunc)scan_object_for_xdomain_refs, NULL, FALSE);
 
        major_collector.iterate_objects (TRUE, TRUE, (IterateObjectCallbackFunc)scan_object_for_xdomain_refs, NULL);
 
@@ -1447,7 +1545,7 @@ mono_gc_clear_domain (MonoDomain * domain)
        }
 
        mono_sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data,
-                       (IterateObjectCallbackFunc)clear_domain_process_minor_object_callback, domain);
+                       (IterateObjectCallbackFunc)clear_domain_process_minor_object_callback, domain, FALSE);
 
        /*Ephemerons and dislinks must be processed before LOS since they might end up pointing
        to memory returned to the OS.*/
@@ -1478,7 +1576,7 @@ mono_gc_clear_domain (MonoDomain * domain)
                        bigobj = bigobj->next;
                        DEBUG (4, fprintf (gc_debug_file, "Freeing large object %p\n",
                                        bigobj->data));
-                       free_large_object (to_free);
+                       mono_sgen_los_free_object (to_free);
                        continue;
                }
                prev = bigobj;
@@ -1600,8 +1698,8 @@ mono_sgen_add_to_global_remset (gpointer ptr)
  * frequently after each object is copied, to achieve better locality and cache
  * usage.
  */
-static void
-drain_gray_stack (GrayQueue *queue)
+static gboolean
+drain_gray_stack (GrayQueue *queue, int max_objs)
 {
        char *obj;
 
@@ -1609,21 +1707,26 @@ drain_gray_stack (GrayQueue *queue)
                for (;;) {
                        GRAY_OBJECT_DEQUEUE (queue, obj);
                        if (!obj)
-                               break;
+                               return TRUE;
                        DEBUG (9, fprintf (gc_debug_file, "Precise gray object scan %p (%s)\n", obj, safe_name (obj)));
                        major_collector.minor_scan_object (obj, queue);
                }
        } else {
+               int i;
+
                if (major_collector.is_parallel && queue == &workers_distribute_gray_queue)
-                       return;
+                       return TRUE;
 
-               for (;;) {
-                       GRAY_OBJECT_DEQUEUE (queue, obj);
-                       if (!obj)
-                               break;
-                       DEBUG (9, fprintf (gc_debug_file, "Precise gray object scan %p (%s)\n", obj, safe_name (obj)));
-                       major_collector.major_scan_object (obj, queue);
-               }
+               do {
+                       for (i = 0; i != max_objs; ++i) {
+                               GRAY_OBJECT_DEQUEUE (queue, obj);
+                               if (!obj)
+                                       return TRUE;
+                               DEBUG (9, fprintf (gc_debug_file, "Precise gray object scan %p (%s)\n", obj, safe_name (obj)));
+                               major_collector.major_scan_object (obj, queue);
+                       }
+               } while (max_objs < 0);
+               return FALSE;
        }
 }
 
@@ -1742,6 +1845,14 @@ pin_objects_from_addresses (GCMemSection *section, void **start, void **end, voi
                start++;
        }
        //printf ("effective pinned: %d (at the end: %d)\n", count, (char*)end_nursery - (char*)last);
+       if (mono_profiler_get_events () & MONO_PROFILE_GC_ROOTS) {
+               GCRootReport report;
+               report.count = 0;
+               for (idx = 0; idx < count; ++idx)
+                       add_profile_gc_root (&report, definitely_pinned [idx], MONO_PROFILE_GC_ROOT_PINNING, 0);
+               notify_gc_roots (&report);
+       }
+       stat_pinned_objects += count;
        return count;
 }
 
@@ -1760,6 +1871,24 @@ mono_sgen_pin_objects_in_section (GCMemSection *section, GrayQueue *queue)
        }
 }
 
+
+void
+mono_sgen_pin_object (void *object, GrayQueue *queue)
+{
+       if (major_collector.is_parallel) {
+               LOCK_PIN_QUEUE;
+               /*object arrives pinned*/
+               pin_stage_ptr (object);
+               ++objects_pinned ;
+               UNLOCK_PIN_QUEUE;
+       } else {
+               SGEN_PIN_OBJECT (object);
+               pin_stage_ptr (object);
+               ++objects_pinned;
+       }
+       GRAY_OBJECT_ENQUEUE (queue, object);
+}
+
 /* Sort the addresses in array in increasing order.
  * Done using a by-the book heap sort. Which has decent and stable performance, is pretty cache efficient.
  */
@@ -1884,7 +2013,7 @@ conservatively_pin_objects_from (void **start, void **end, void *start_nursery,
                                pin_stage_ptr ((void*)addr);
                        if (heap_dump_file)
                                pin_stats_register_address ((char*)addr, pin_type);
-                       DEBUG (6, if (count) fprintf (gc_debug_file, "Pinning address %p\n", (void*)addr));
+                       DEBUG (6, if (count) fprintf (gc_debug_file, "Pinning address %p from %p\n", (void*)addr, start));
                        count++;
                }
                start++;
@@ -1975,7 +2104,7 @@ precisely_scan_objects_from (CopyOrMarkObjectFunc copy_func, void** start_root,
                        if ((desc & 1) && *start_root) {
                                copy_func (start_root, queue);
                                DEBUG (9, fprintf (gc_debug_file, "Overwrote root at %p with %p\n", start_root, *start_root));
-                               drain_gray_stack (queue);
+                               drain_gray_stack (queue, -1);
                        }
                        desc >>= 1;
                        start_root++;
@@ -1993,7 +2122,7 @@ precisely_scan_objects_from (CopyOrMarkObjectFunc copy_func, void** start_root,
                                if ((bmap & 1) && *objptr) {
                                        copy_func (objptr, queue);
                                        DEBUG (9, fprintf (gc_debug_file, "Overwrote root at %p with %p\n", objptr, *objptr));
-                                       drain_gray_stack (queue);
+                                       drain_gray_stack (queue, -1);
                                }
                                bmap >>= 1;
                                ++objptr;
@@ -2018,6 +2147,13 @@ precisely_scan_objects_from (CopyOrMarkObjectFunc copy_func, void** start_root,
        }
 }
 
+static void
+reset_heap_boundaries (void)
+{
+       lowest_heap_address = ~(mword)0;
+       highest_heap_address = 0;
+}
+
 void
 mono_sgen_update_heap_boundaries (mword low, mword high)
 {
@@ -2138,6 +2274,118 @@ mono_gc_get_nursery (int *shift_bits, size_t *size)
        return nursery_start;
 }
 
+gboolean
+mono_gc_precise_stack_mark_enabled (void)
+{
+       return !conservative_stack_mark;
+}
+
+FILE *
+mono_gc_get_logfile (void)
+{
+       return mono_sgen_get_logfile ();
+}
+
+static void
+report_finalizer_roots_list (FinalizeEntry *list)
+{
+       GCRootReport report;
+       FinalizeEntry *fin;
+
+       report.count = 0;
+       for (fin = list; fin; fin = fin->next) {
+               if (!fin->object)
+                       continue;
+               add_profile_gc_root (&report, fin->object, MONO_PROFILE_GC_ROOT_FINALIZER, 0);
+       }
+       notify_gc_roots (&report);
+}
+
+static void
+report_finalizer_roots (void)
+{
+       report_finalizer_roots_list (fin_ready_list);
+       report_finalizer_roots_list (critical_fin_list);
+}
+
+static GCRootReport *root_report;
+
+static void
+single_arg_report_root (void **obj)
+{
+       if (*obj)
+               add_profile_gc_root (root_report, *obj, MONO_PROFILE_GC_ROOT_OTHER, 0);
+}
+
+static void
+precisely_report_roots_from (GCRootReport *report, void** start_root, void** end_root, mword desc)
+{
+       switch (desc & ROOT_DESC_TYPE_MASK) {
+       case ROOT_DESC_BITMAP:
+               desc >>= ROOT_DESC_TYPE_SHIFT;
+               while (desc) {
+                       if ((desc & 1) && *start_root) {
+                               add_profile_gc_root (report, *start_root, MONO_PROFILE_GC_ROOT_OTHER, 0);
+                       }
+                       desc >>= 1;
+                       start_root++;
+               }
+               return;
+       case ROOT_DESC_COMPLEX: {
+               gsize *bitmap_data = complex_descriptors + (desc >> ROOT_DESC_TYPE_SHIFT);
+               int bwords = (*bitmap_data) - 1;
+               void **start_run = start_root;
+               bitmap_data++;
+               while (bwords-- > 0) {
+                       gsize bmap = *bitmap_data++;
+                       void **objptr = start_run;
+                       while (bmap) {
+                               if ((bmap & 1) && *objptr) {
+                                       add_profile_gc_root (report, *objptr, MONO_PROFILE_GC_ROOT_OTHER, 0);
+                               }
+                               bmap >>= 1;
+                               ++objptr;
+                       }
+                       start_run += GC_BITS_PER_WORD;
+               }
+               break;
+       }
+       case ROOT_DESC_USER: {
+               MonoGCRootMarkFunc marker = user_descriptors [desc >> ROOT_DESC_TYPE_SHIFT];
+               root_report = report;
+               marker (start_root, single_arg_report_root);
+               break;
+       }
+       case ROOT_DESC_RUN_LEN:
+               g_assert_not_reached ();
+       default:
+               g_assert_not_reached ();
+       }
+}
+
+static void
+report_registered_roots_by_type (int root_type)
+{
+       GCRootReport report;
+       int i;
+       RootRecord *root;
+       report.count = 0;
+       for (i = 0; i < roots_hash_size [root_type]; ++i) {
+               for (root = roots_hash [root_type][i]; root; root = root->next) {
+                       DEBUG (6, fprintf (gc_debug_file, "Precise root scan %p-%p (desc: %p)\n", root->start_root, root->end_root, (void*)root->root_desc));
+                       precisely_report_roots_from (&report, (void**)root->start_root, (void**)root->end_root, root->root_desc);
+               }
+       }
+       notify_gc_roots (&report);
+}
+
+static void
+report_registered_roots (void)
+{
+       report_registered_roots_by_type (ROOT_TYPE_NORMAL);
+       report_registered_roots_by_type (ROOT_TYPE_WBARRIER);
+}
+
 static void
 scan_finalizer_entries (CopyOrMarkObjectFunc copy_func, FinalizeEntry *list, GrayQueue *queue)
 {
@@ -2213,6 +2461,28 @@ get_finalize_entry_hash_table (int generation)
        }
 }
 
+static MonoObject **finalized_array = NULL;
+static int finalized_array_capacity = 0;
+static int finalized_array_entries = 0;
+
+static void
+bridge_register_finalized_object (MonoObject *object)
+{
+       if (!finalized_array)
+               return;
+
+       if (finalized_array_entries >= finalized_array_capacity) {
+               MonoObject **new_array;
+               g_assert (finalized_array_entries == finalized_array_capacity);
+               finalized_array_capacity *= 2;
+               new_array = mono_sgen_alloc_internal_dynamic (sizeof (MonoObject*) * finalized_array_capacity, INTERNAL_MEM_BRIDGE_DATA);
+               memcpy (new_array, finalized_array, sizeof (MonoObject*) * finalized_array_entries);
+               mono_sgen_free_internal_dynamic (finalized_array, sizeof (MonoObject*) * finalized_array_entries, INTERNAL_MEM_BRIDGE_DATA);
+               finalized_array = new_array;
+       }
+       finalized_array [finalized_array_entries++] = object;
+}
+
 static void
 finish_gray_stack (char *start_addr, char *end_addr, int generation, GrayQueue *queue)
 {
@@ -2220,6 +2490,7 @@ finish_gray_stack (char *start_addr, char *end_addr, int generation, GrayQueue *
        TV_DECLARE (btv);
        int fin_ready;
        int ephemeron_rounds = 0;
+       int num_loops;
        CopyOrMarkObjectFunc copy_func = current_collection_generation == GENERATION_NURSERY ? major_collector.copy_object : major_collector.copy_or_mark_object;
 
        /*
@@ -2235,9 +2506,24 @@ finish_gray_stack (char *start_addr, char *end_addr, int generation, GrayQueue *
         *   To achieve better cache locality and cache usage, we drain the gray stack 
         * frequently, after each object is copied, and just finish the work here.
         */
-       drain_gray_stack (queue);
+       drain_gray_stack (queue, -1);
        TV_GETTIME (atv);
        DEBUG (2, fprintf (gc_debug_file, "%s generation done\n", generation_name (generation)));
+
+       /*
+       We must clear weak links that don't track resurrection before processing object ready for
+       finalization so they can be cleared before that.
+       */
+       null_link_in_range (copy_func, start_addr, end_addr, generation, TRUE, queue);
+       if (generation == GENERATION_OLD)
+               null_link_in_range (copy_func, start_addr, end_addr, GENERATION_NURSERY, TRUE, queue);
+
+       if (finalized_array == NULL && mono_sgen_need_bridge_processing ()) {
+               finalized_array_capacity = 32;
+               finalized_array = mono_sgen_alloc_internal_dynamic (sizeof (MonoObject*) * finalized_array_capacity, INTERNAL_MEM_BRIDGE_DATA);
+       }
+       finalized_array_entries = 0;
+
        /* walk the finalization queue and move also the objects that need to be
         * finalized: use the finalized objects as new roots so the objects they depend
         * on are also not reclaimed. As with the roots above, only objects in the nursery
@@ -2245,6 +2531,7 @@ finish_gray_stack (char *start_addr, char *end_addr, int generation, GrayQueue *
         * We need a loop here, since objects ready for finalizers may reference other objects
         * that are fin-ready. Speedup with a flag?
         */
+       num_loops = 0;
        do {
                /*
                 * Walk the ephemeron tables marking all values with reachable keys. This must be completely done
@@ -2256,7 +2543,7 @@ finish_gray_stack (char *start_addr, char *end_addr, int generation, GrayQueue *
                int done_with_ephemerons = 0;
                do {
                        done_with_ephemerons = mark_ephemerons_in_range (copy_func, start_addr, end_addr, queue);
-                       drain_gray_stack (queue);
+                       drain_gray_stack (queue, -1);
                        ++ephemeron_rounds;
                } while (!done_with_ephemerons);
 
@@ -2265,11 +2552,20 @@ finish_gray_stack (char *start_addr, char *end_addr, int generation, GrayQueue *
                if (generation == GENERATION_OLD)
                        finalize_in_range (copy_func, nursery_start, nursery_real_end, GENERATION_NURSERY, queue);
 
+               if (fin_ready != num_ready_finalizers) {
+                       ++num_loops;
+                       if (finalized_array != NULL)
+                               mono_sgen_bridge_processing (finalized_array_entries, finalized_array);
+               }
+
                /* drain the new stack that might have been created */
                DEBUG (6, fprintf (gc_debug_file, "Precise scan of gray area post fin\n"));
-               drain_gray_stack (queue);
+               drain_gray_stack (queue, -1);
        } while (fin_ready != num_ready_finalizers);
 
+       if (mono_sgen_need_bridge_processing ())
+               g_assert (num_loops <= 1);
+
        /*
         * Clear ephemeron pairs with unreachable keys.
         * We pass the copy func so we can figure out if an array was promoted or not.
@@ -2289,12 +2585,12 @@ finish_gray_stack (char *start_addr, char *end_addr, int generation, GrayQueue *
         */
        g_assert (gray_object_queue_is_empty (queue));
        for (;;) {
-               null_link_in_range (copy_func, start_addr, end_addr, generation, queue);
+               null_link_in_range (copy_func, start_addr, end_addr, generation, FALSE, queue);
                if (generation == GENERATION_OLD)
-                       null_link_in_range (copy_func, start_addr, end_addr, GENERATION_NURSERY, queue);
+                       null_link_in_range (copy_func, start_addr, end_addr, GENERATION_NURSERY, FALSE, queue);
                if (gray_object_queue_is_empty (queue))
                        break;
-               drain_gray_stack (queue);
+               drain_gray_stack (queue, -1);
        }
 
        g_assert (gray_object_queue_is_empty (queue));
@@ -2556,6 +2852,7 @@ init_stats (void)
        mono_counters_register ("Major sweep", MONO_COUNTER_GC | MONO_COUNTER_LONG, &time_major_sweep);
        mono_counters_register ("Major fragment creation", MONO_COUNTER_GC | MONO_COUNTER_LONG, &time_major_fragment_creation);
 
+       mono_counters_register ("Number of pinned objects", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_pinned_objects);
 
 #ifdef HEAVY_STATISTICS
        mono_counters_register ("WBarrier set field", MONO_COUNTER_GC | MONO_COUNTER_INT, &stat_wbarrier_set_field);
@@ -2602,11 +2899,81 @@ init_stats (void)
        inited = TRUE;
 }
 
+static gboolean need_calculate_minor_collection_allowance;
+
+static int last_collection_old_num_major_sections;
+static mword last_collection_los_memory_usage = 0;
+static mword last_collection_old_los_memory_usage;
+static mword last_collection_los_memory_alloced;
+
+static void
+reset_minor_collection_allowance (void)
+{
+       need_calculate_minor_collection_allowance = TRUE;
+}
+
+static void
+try_calculate_minor_collection_allowance (gboolean overwrite)
+{
+       int num_major_sections, num_major_sections_saved, save_target, allowance_target;
+       mword los_memory_saved;
+
+       if (overwrite)
+               g_assert (need_calculate_minor_collection_allowance);
+
+       if (!need_calculate_minor_collection_allowance)
+               return;
+
+       if (!*major_collector.have_swept) {
+               if (overwrite)
+                       minor_collection_allowance = MIN_MINOR_COLLECTION_ALLOWANCE;
+               return;
+       }
+
+       num_major_sections = major_collector.get_num_major_sections ();
+
+       num_major_sections_saved = MAX (last_collection_old_num_major_sections - num_major_sections, 0);
+       los_memory_saved = MAX (last_collection_old_los_memory_usage - last_collection_los_memory_usage, 1);
+
+       save_target = ((num_major_sections * major_collector.section_size) + los_memory_saved) / 2;
+
+       /*
+        * We aim to allow the allocation of as many sections as is
+        * necessary to reclaim save_target sections in the next
+        * collection.  We assume the collection pattern won't change.
+        * In the last cycle, we had num_major_sections_saved for
+        * minor_collection_sections_alloced.  Assuming things won't
+        * change, this must be the same ratio as save_target for
+        * allowance_target, i.e.
+        *
+        *    num_major_sections_saved            save_target
+        * --------------------------------- == ----------------
+        * minor_collection_sections_alloced    allowance_target
+        *
+        * hence:
+        */
+       allowance_target = (mword)((double)save_target * (double)(minor_collection_sections_alloced * major_collector.section_size + last_collection_los_memory_alloced) / (double)(num_major_sections_saved * major_collector.section_size + los_memory_saved));
+
+       minor_collection_allowance = MAX (MIN (allowance_target, num_major_sections * major_collector.section_size + los_memory_usage), MIN_MINOR_COLLECTION_ALLOWANCE);
+
+       if (major_collector.have_computed_minor_collection_allowance)
+               major_collector.have_computed_minor_collection_allowance ();
+
+       need_calculate_minor_collection_allowance = FALSE;
+}
+
 static gboolean
-need_major_collection (void)
+need_major_collection (mword space_needed)
+{
+       mword los_alloced = los_memory_usage - MIN (last_collection_los_memory_usage, los_memory_usage);
+       return (space_needed > available_free_space ()) ||
+               minor_collection_sections_alloced * major_collector.section_size + los_alloced > minor_collection_allowance;
+}
+
+gboolean
+mono_sgen_need_major_collection (mword space_needed)
 {
-       mword los_alloced = los_memory_usage - MIN (last_los_memory_usage, los_memory_usage);
-       return minor_collection_sections_alloced * major_collector.section_size + los_alloced > minor_collection_allowance;
+       return need_major_collection (space_needed);
 }
 
 /*
@@ -2616,6 +2983,7 @@ need_major_collection (void)
 static gboolean
 collect_nursery (size_t requested_size)
 {
+       gboolean needs_major;
        size_t max_garbage_amount;
        char *orig_nursery_next;
        TV_DECLARE (all_atv);
@@ -2631,6 +2999,7 @@ collect_nursery (size_t requested_size)
        check_scan_starts ();
 
        degraded_mode = 0;
+       objects_pinned = 0;
        orig_nursery_next = nursery_next;
        nursery_next = MAX (nursery_next, nursery_last_pinned_end);
        /* FIXME: optimize later to use the higher address where an object can be present */
@@ -2657,6 +3026,8 @@ collect_nursery (size_t requested_size)
 
        major_collector.start_nursery_collection ();
 
+       try_calculate_minor_collection_allowance (FALSE);
+
        gray_object_queue_init (&gray_queue, mono_sgen_get_unmanaged_allocator ());
 
        num_minor_gcs++;
@@ -2700,8 +3071,12 @@ collect_nursery (size_t requested_size)
                time_minor_scan_card_table += TV_ELAPSED_MS (atv, btv);
        }
 
-       drain_gray_stack (&gray_queue);
+       drain_gray_stack (&gray_queue, -1);
 
+       if (mono_profiler_get_events () & MONO_PROFILE_GC_ROOTS)
+               report_registered_roots ();
+       if (mono_profiler_get_events () & MONO_PROFILE_GC_ROOTS)
+               report_finalizer_roots ();
        TV_GETTIME (atv);
        time_minor_scan_pinned += TV_ELAPSED_MS (btv, atv);
        /* registered roots, this includes static fields */
@@ -2720,6 +3095,13 @@ collect_nursery (size_t requested_size)
        time_minor_finish_gray_stack += TV_ELAPSED_MS (btv, atv);
        mono_profiler_gc_event (MONO_GC_EVENT_MARK_END, 0);
 
+       if (objects_pinned) {
+               evacuate_pin_staging_area ();
+               optimize_pin_queue (0);
+               nursery_section->pin_queue_start = pin_queue;
+               nursery_section->pin_queue_num_entries = next_pin_slot;
+       }
+
        /* walk the pin_queue, build up the fragment list of free memory, unmark
         * pinned objects as we go, memzero() the empty fragments so they are ready for the
         * next allocations.
@@ -2760,9 +3142,12 @@ collect_nursery (size_t requested_size)
 
        binary_protocol_flush_buffers (FALSE);
 
+       /*objects are late pinned because of lack of memory, so a major is a good call*/
+       needs_major = need_major_collection (0) || objects_pinned;
        current_collection_generation = -1;
+       objects_pinned = 0;
 
-       return need_major_collection ();
+       return needs_major;
 }
 
 static void
@@ -2778,18 +3163,19 @@ major_do_collection (const char *reason)
         */
        char *heap_start = NULL;
        char *heap_end = (char*)-1;
-       int old_num_major_sections = major_collector.get_num_major_sections ();
-       int num_major_sections, num_major_sections_saved, save_target, allowance_target;
-       mword los_memory_saved, los_memory_alloced, old_los_memory_usage;
+       int old_next_pin_slot;
 
        mono_perfcounters->gc_collections1++;
 
+       last_collection_old_num_major_sections = major_collector.get_num_major_sections ();
+
        /*
         * A domain could have been freed, resulting in
-        * los_memory_usage being less than last_los_memory_usage.
+        * los_memory_usage being less than last_collection_los_memory_usage.
         */
-       los_memory_alloced = los_memory_usage - MIN (last_los_memory_usage, los_memory_usage);
-       old_los_memory_usage = los_memory_usage;
+       last_collection_los_memory_alloced = los_memory_usage - MIN (last_collection_los_memory_usage, los_memory_usage);
+       last_collection_old_los_memory_usage = los_memory_usage;
+       objects_pinned = 0;
 
        //count_ref_nonref_objs ();
        //consistency_check ();
@@ -2815,9 +3201,6 @@ major_do_collection (const char *reason)
        TV_GETTIME (btv);
        time_major_pre_collection_fragment_clear += TV_ELAPSED_MS (atv, btv);
 
-       if (xdomain_checks)
-               check_for_xdomain_refs ();
-
        nursery_section->next_data = nursery_real_end;
        /* we should also coalesce scanning from sections close to each other
         * and deal with pointers outside of the sections later.
@@ -2826,6 +3209,12 @@ major_do_collection (const char *reason)
        if (major_collector.start_major_collection)
                major_collector.start_major_collection ();
 
+       *major_collector.have_swept = FALSE;
+       reset_minor_collection_allowance ();
+
+       if (xdomain_checks)
+               check_for_xdomain_refs ();
+
        /* The remsets are not useful for a major collection */
        clear_remsets ();
        global_remset_cache_clear ();
@@ -2870,6 +3259,7 @@ major_do_collection (const char *reason)
        /* second pass for the sections */
        mono_sgen_pin_objects_in_section (nursery_section, WORKERS_DISTRIBUTE_GRAY_QUEUE);
        major_collector.pin_objects (WORKERS_DISTRIBUTE_GRAY_QUEUE);
+       old_next_pin_slot = next_pin_slot;
 
        TV_GETTIME (btv);
        time_major_pinning += TV_ELAPSED_MS (atv, btv);
@@ -2878,8 +3268,10 @@ major_do_collection (const char *reason)
 
        major_collector.init_to_space ();
 
-       workers_start_all_workers (1);
+       workers_start_all_workers ();
 
+       if (mono_profiler_get_events () & MONO_PROFILE_GC_ROOTS)
+               report_registered_roots ();
        TV_GETTIME (atv);
        time_major_scan_pinned += TV_ELAPSED_MS (btv, atv);
 
@@ -2899,6 +3291,8 @@ major_do_collection (const char *reason)
        TV_GETTIME (btv);
        time_major_scan_alloc_pinned += TV_ELAPSED_MS (atv, btv);
 
+       if (mono_profiler_get_events () & MONO_PROFILE_GC_ROOTS)
+               report_finalizer_roots ();
        /* scan the list of objects ready for finalization */
        scan_finalizer_entries (major_collector.copy_or_mark_object, fin_ready_list, WORKERS_DISTRIBUTE_GRAY_QUEUE);
        scan_finalizer_entries (major_collector.copy_or_mark_object, critical_fin_list, WORKERS_DISTRIBUTE_GRAY_QUEUE);
@@ -2912,10 +3306,9 @@ major_do_collection (const char *reason)
        if (major_collector.is_parallel) {
                while (!gray_object_queue_is_empty (WORKERS_DISTRIBUTE_GRAY_QUEUE)) {
                        workers_distribute_gray_queue_sections ();
-                       usleep (2000);
+                       usleep (1000);
                }
        }
-       workers_change_num_working (-1);
        workers_join ();
 
        if (major_collector.is_parallel)
@@ -2926,11 +3319,33 @@ major_do_collection (const char *reason)
        TV_GETTIME (atv);
        time_major_finish_gray_stack += TV_ELAPSED_MS (btv, atv);
 
+       /*
+        * The (single-threaded) finalization code might have done
+        * some copying/marking so we can only reset the GC thread's
+        * worker data here instead of earlier when we joined the
+        * workers.
+        */
+       if (major_collector.reset_worker_data)
+               major_collector.reset_worker_data (workers_gc_thread_data.major_collector_data);
+
+       if (objects_pinned) {
+               /*This is slow, but we just OOM'd*/
+               mono_sgen_pin_queue_clear_discarded_entries (nursery_section, old_next_pin_slot);
+               evacuate_pin_staging_area ();
+               optimize_pin_queue (0);
+               mono_sgen_find_section_pin_queue_start_end (nursery_section);
+               objects_pinned = 0;
+       }
+
+       reset_heap_boundaries ();
+       mono_sgen_update_heap_boundaries ((mword)nursery_start, (mword)nursery_real_end);
+
        /* sweep the big objects list */
        prevbo = NULL;
        for (bigobj = los_object_list; bigobj;) {
                if (object_is_pinned (bigobj->data)) {
                        unpin_object (bigobj->data);
+                       mono_sgen_update_heap_boundaries ((mword)bigobj->data, (mword)bigobj->data + bigobj->size);
                } else {
                        LOSObject *to_free;
                        /* not referenced anywhere, so we can free it */
@@ -2940,7 +3355,7 @@ major_do_collection (const char *reason)
                                los_object_list = bigobj->next;
                        to_free = bigobj;
                        bigobj = bigobj->next;
-                       free_large_object (to_free);
+                       mono_sgen_los_free_object (to_free);
                        continue;
                }
                prevbo = bigobj;
@@ -2950,7 +3365,7 @@ major_do_collection (const char *reason)
        TV_GETTIME (btv);
        time_major_free_bigobjs += TV_ELAPSED_MS (atv, btv);
 
-       los_sweep ();
+       mono_sgen_los_sweep ();
 
        TV_GETTIME (atv);
        time_major_los_sweep += TV_ELAPSED_MS (btv, atv);
@@ -2985,33 +3400,10 @@ major_do_collection (const char *reason)
 
        g_assert (gray_object_queue_is_empty (&gray_queue));
 
-       num_major_sections = major_collector.get_num_major_sections ();
-
-       num_major_sections_saved = MAX (old_num_major_sections - num_major_sections, 0);
-       los_memory_saved = MAX (old_los_memory_usage - los_memory_usage, 1);
-
-       save_target = ((num_major_sections * major_collector.section_size) + los_memory_saved) / 2;
-       /*
-        * We aim to allow the allocation of as many sections as is
-        * necessary to reclaim save_target sections in the next
-        * collection.  We assume the collection pattern won't change.
-        * In the last cycle, we had num_major_sections_saved for
-        * minor_collection_sections_alloced.  Assuming things won't
-        * change, this must be the same ratio as save_target for
-        * allowance_target, i.e.
-        *
-        *    num_major_sections_saved            save_target
-        * --------------------------------- == ----------------
-        * minor_collection_sections_alloced    allowance_target
-        *
-        * hence:
-        */
-       allowance_target = (mword)((double)save_target * (double)(minor_collection_sections_alloced * major_collector.section_size + los_memory_alloced) / (double)(num_major_sections_saved * major_collector.section_size + los_memory_saved));
-
-       minor_collection_allowance = MAX (MIN (allowance_target, num_major_sections * major_collector.section_size + los_memory_usage), MIN_MINOR_COLLECTION_ALLOWANCE);
+       try_calculate_minor_collection_allowance (TRUE);
 
        minor_collection_sections_alloced = 0;
-       last_los_memory_usage = los_memory_usage;
+       last_collection_los_memory_usage = los_memory_usage;
 
        major_collector.finish_major_collection ();
 
@@ -3035,6 +3427,16 @@ major_collection (const char *reason)
        current_collection_generation = -1;
 }
 
+void
+sgen_collect_major_no_lock (const char *reason)
+{
+        mono_profiler_gc_event (MONO_GC_EVENT_START, 1);
+        stop_world (1);
+        major_collection (reason);
+        restart_world (1);
+        mono_profiler_gc_event (MONO_GC_EVENT_END, 1);
+}
+
 /*
  * When deciding if it's better to collect or to expand, keep track
  * of how much garbage was reclaimed with the last collection: if it's too
@@ -3232,7 +3634,7 @@ search_fragment_for_size_range (size_t desired_size, size_t minimum_size)
 static void*
 alloc_degraded (MonoVTable *vtable, size_t size)
 {
-       if (need_major_collection ()) {
+       if (need_major_collection (0)) {
                mono_profiler_gc_event (MONO_GC_EVENT_START, 1);
                stop_world (1);
                major_collection ("degraded overflow");
@@ -3240,7 +3642,6 @@ alloc_degraded (MonoVTable *vtable, size_t size)
                mono_profiler_gc_event (MONO_GC_EVENT_END, 1);
        }
 
-       degraded_mode += size;
        return major_collector.alloc_degraded (vtable, size);
 }
 
@@ -3271,13 +3672,16 @@ mono_gc_alloc_obj_nolock (MonoVTable *vtable, size_t size)
        g_assert (vtable->gc_descr);
 
        if (G_UNLIKELY (collect_before_allocs)) {
-               if (nursery_section) {
+               static int alloc_count;
+
+               InterlockedIncrement (&alloc_count);
+               if (((alloc_count % collect_before_allocs) == 0) && nursery_section) {
                        mono_profiler_gc_event (MONO_GC_EVENT_START, 0);
                        stop_world (0);
                        collect_nursery (0);
                        restart_world (0);
                        mono_profiler_gc_event (MONO_GC_EVENT_END, 0);
-                       if (!degraded_mode && !search_fragment_for_size (size)) {
+                       if (!degraded_mode && !search_fragment_for_size (size) && size <= MAX_SMALL_OBJ_SIZE) {
                                // FIXME:
                                g_assert_not_reached ();
                        }
@@ -3296,7 +3700,7 @@ mono_gc_alloc_obj_nolock (MonoVTable *vtable, size_t size)
         */
 
        if (size > MAX_SMALL_OBJ_SIZE) {
-               p = alloc_large_inner (vtable, size);
+               p = mono_sgen_los_alloc_large_inner (vtable, size);
        } else {
                /* tlab_next and tlab_temp_end are TLS vars so accessing them might be expensive */
 
@@ -3429,9 +3833,11 @@ mono_gc_alloc_obj_nolock (MonoVTable *vtable, size_t size)
                }
        }
 
-       DEBUG (6, fprintf (gc_debug_file, "Allocated object %p, vtable: %p (%s), size: %zd\n", p, vtable, vtable->klass->name, size));
-       binary_protocol_alloc (p, vtable, size);
-       *p = vtable;
+       if (G_LIKELY (p)) {
+               DEBUG (6, fprintf (gc_debug_file, "Allocated object %p, vtable: %p (%s), size: %zd\n", p, vtable, vtable->klass->name, size));
+               binary_protocol_alloc (p, vtable, size);
+               *p = vtable;
+       }
 
        return p;
 }
@@ -3495,6 +3901,8 @@ mono_gc_alloc_obj (MonoVTable *vtable, size_t size)
        LOCK_GC;
        res = mono_gc_alloc_obj_nolock (vtable, size);
        UNLOCK_GC;
+       if (G_UNLIKELY (!res))
+               return mono_gc_out_of_memory (size);
        return res;
 }
 
@@ -3517,6 +3925,11 @@ mono_gc_alloc_vector (MonoVTable *vtable, size_t size, uintptr_t max_length)
        LOCK_GC;
 
        arr = mono_gc_alloc_obj_nolock (vtable, size);
+       if (G_UNLIKELY (!arr)) {
+               UNLOCK_GC;
+               return mono_gc_out_of_memory (size);
+       }
+
        arr->max_length = max_length;
 
        UNLOCK_GC;
@@ -3533,6 +3946,11 @@ mono_gc_alloc_array (MonoVTable *vtable, size_t size, uintptr_t max_length, uint
        LOCK_GC;
 
        arr = mono_gc_alloc_obj_nolock (vtable, size);
+       if (G_UNLIKELY (!arr)) {
+               UNLOCK_GC;
+               return mono_gc_out_of_memory (size);
+       }
+
        arr->max_length = max_length;
 
        bounds = (MonoArrayBounds*)((char*)arr + size - bounds_size);
@@ -3562,6 +3980,11 @@ mono_gc_alloc_string (MonoVTable *vtable, size_t size, gint32 len)
        LOCK_GC;
 
        str = mono_gc_alloc_obj_nolock (vtable, size);
+       if (G_UNLIKELY (!str)) {
+               UNLOCK_GC;
+               return mono_gc_out_of_memory (size);
+       }
+
        str->length = len;
 
        UNLOCK_GC;
@@ -3576,24 +3999,38 @@ mono_gc_alloc_string (MonoVTable *vtable, size_t size, gint32 len)
 void*
 mono_gc_alloc_pinned_obj (MonoVTable *vtable, size_t size)
 {
-       /* FIXME: handle OOM */
        void **p;
        size = ALIGN_UP (size);
        LOCK_GC;
+
        if (size > MAX_SMALL_OBJ_SIZE) {
                /* large objects are always pinned anyway */
-               p = alloc_large_inner (vtable, size);
+               p = mono_sgen_los_alloc_large_inner (vtable, size);
        } else {
                DEBUG (9, g_assert (vtable->klass->inited));
-               p = major_collector.alloc_small_pinned_obj (size, vtable->klass->has_references);
+               p = major_collector.alloc_small_pinned_obj (size, SGEN_VTABLE_HAS_REFERENCES (vtable));
+       }
+       if (G_LIKELY (p)) {
+               DEBUG (6, fprintf (gc_debug_file, "Allocated pinned object %p, vtable: %p (%s), size: %zd\n", p, vtable, vtable->klass->name, size));
+               binary_protocol_alloc_pinned (p, vtable, size);
+               *p = vtable;
        }
-       DEBUG (6, fprintf (gc_debug_file, "Allocated pinned object %p, vtable: %p (%s), size: %zd\n", p, vtable, vtable->klass->name, size));
-       binary_protocol_alloc_pinned (p, vtable, size);
-       *p = vtable;
        UNLOCK_GC;
        return p;
 }
 
+void*
+mono_gc_alloc_mature (MonoVTable *vtable)
+{
+       void **res;
+       size_t size = ALIGN_UP (vtable->klass->instance_size);
+       LOCK_GC;
+       res = alloc_degraded (vtable, size);
+       *res = vtable;
+       UNLOCK_GC;
+       return res;
+}
+
 /*
  * ######################################################################
  * ########  Finalization support
@@ -3698,6 +4135,7 @@ finalize_in_range (CopyOrMarkObjectFunc copy_func, char *start, char *end, int g
                                        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;
@@ -3752,6 +4190,16 @@ object_is_reachable (char *object, char *start, char *end)
        return !object_is_fin_ready (object) || major_collector.is_object_live (object);
 }
 
+gboolean
+mono_sgen_object_is_live (void *obj)
+{
+       if (ptr_in_nursery (obj))
+               return object_is_pinned (obj);
+       if (current_collection_generation == GENERATION_NURSERY)
+               return FALSE;
+       return major_collector.is_object_live (obj);
+}
+
 /* LOCKING: requires that the GC lock is held */
 static void
 null_ephemerons_for_domain (MonoDomain *domain)
@@ -3913,7 +4361,7 @@ mark_ephemerons_in_range (CopyOrMarkObjectFunc copy_func, char *start, char *end
 
 /* LOCKING: requires that the GC lock is held */
 static void
-null_link_in_range (CopyOrMarkObjectFunc copy_func, char *start, char *end, int generation, GrayQueue *queue)
+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;
@@ -3925,9 +4373,17 @@ null_link_in_range (CopyOrMarkObjectFunc copy_func, char *start, char *end, int
        for (i = 0; i < disappearing_link_hash_size; ++i) {
                prev = NULL;
                for (entry = disappearing_link_hash [i]; entry;) {
-                       char *object = DISLINK_OBJECT (entry);
+                       char *object;
+                       gboolean track = DISLINK_TRACK (entry);
+                       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)) {
-                               gboolean track = DISLINK_TRACK (entry);
                                if (!track && object_is_fin_ready (object)) {
                                        void **p = entry->link;
                                        DisappearingLink *old;
@@ -4825,7 +5281,6 @@ mono_gc_conservatively_scan_area (void *start, void *end)
 void*
 mono_gc_scan_object (void *obj)
 {
-       g_assert_not_reached ();
        if (current_collection_generation == GENERATION_NURSERY)
                major_collector.copy_object (&obj, &gray_queue);
        else
@@ -4867,7 +5322,7 @@ scan_thread_data (void *start_nursery, void *end_nursery, gboolean precise)
 static void
 find_pinning_ref_from_thread (char *obj, size_t size)
 {
-       int i;
+       int i, j;
        SgenThreadInfo *info;
        char *endobj = obj + size;
 
@@ -4883,7 +5338,12 @@ find_pinning_ref_from_thread (char *obj, size_t size)
                                start++;
                        }
 
-                       /* FIXME: check info->stopped_regs */
+                       for (j = 0; j < ARCH_NUM_REGS; ++j) {
+                               mword w = (mword)info->stopped_regs [j];
+
+                               if (w >= (mword)obj && w < (mword)obj + size)
+                                       DEBUG (0, fprintf (gc_debug_file, "Object %p referenced in saved reg %d of thread %p (id %p)\n", obj, j, info, (gpointer)info->id));
+                       }
                }
        }
 }
@@ -5376,6 +5836,12 @@ unregister_current_thread (void)
        } else {
                prev->next = p->next;
        }
+
+       if (gc_callbacks.thread_detach_func) {
+               gc_callbacks.thread_detach_func (p->runtime_data);
+               p->runtime_data = NULL;
+       }
+
        if (p->remset) {
                if (freed_thread_remsets) {
                        for (rset = p->remset; rset->next; rset = rset->next)
@@ -5395,7 +5861,15 @@ unregister_current_thread (void)
 static void
 unregister_thread (void *k)
 {
-       g_assert (!mono_domain_get ());
+       /* If a delegate is passed to native code and invoked on a thread we dont
+        * know about, the jit will register it with mono_jit_thead_attach, but
+        * we have no way of knowing when that thread goes away.  SGen has a TSD
+        * so we assume that if the domain is still registered, we can detach
+        * the thread
+        */
+       if (mono_domain_get ())
+               mono_thread_detach (mono_thread_current ());
+
        LOCK_GC;
        unregister_current_thread ();
        UNLOCK_GC;
@@ -5409,8 +5883,13 @@ mono_gc_register_thread (void *baseptr)
        LOCK_GC;
        init_stats ();
        info = mono_sgen_thread_info_lookup (ARCH_GET_THREAD ());
-       if (info == NULL)
+       if (info == NULL) {
                info = gc_register_current_thread (baseptr);
+       } else {
+               /* The main thread might get registered before callbacks are set */
+               if (gc_callbacks.thread_attach_func && !info->runtime_data)
+                       info->runtime_data = gc_callbacks.thread_attach_func ();
+       }
        UNLOCK_GC;
 
        /* Need a better place to initialize this */
@@ -5421,6 +5900,26 @@ mono_gc_register_thread (void *baseptr)
        return info != NULL;
 }
 
+/*
+ * mono_gc_set_stack_end:
+ *
+ *   Set the end of the current threads stack to STACK_END. The stack space between 
+ * STACK_END and the real end of the threads stack will not be scanned during collections.
+ */
+void
+mono_gc_set_stack_end (void *stack_end)
+{
+       SgenThreadInfo *info;
+
+       LOCK_GC;
+       info = mono_sgen_thread_info_lookup (ARCH_GET_THREAD ());
+       if (info) {
+               g_assert (stack_end < info->stack_end);
+               info->stack_end = stack_end;
+       }
+       UNLOCK_GC;
+}
+
 #if USE_PTHREAD_INTERCEPT
 
 typedef struct {
@@ -5669,8 +6168,10 @@ mono_gc_wbarrier_arrayref_copy (gpointer dest_ptr, gpointer src_ptr, int count)
 static char *found_obj;
 
 static void
-find_object_for_ptr_callback (char *obj, size_t size, char *ptr)
+find_object_for_ptr_callback (char *obj, size_t size, void *user_data)
 {
+       char *ptr = user_data;
+
        if (ptr >= obj && ptr < obj + size) {
                g_assert (!found_obj);
                found_obj = obj;
@@ -5682,27 +6183,25 @@ char* find_object_for_ptr (char *ptr);
 char*
 find_object_for_ptr (char *ptr)
 {
-       LOSObject *bigobj;
-
        if (ptr >= nursery_section->data && ptr < nursery_section->end_data) {
                found_obj = NULL;
                mono_sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data,
-                               (IterateObjectCallbackFunc)find_object_for_ptr_callback, ptr);
+                               find_object_for_ptr_callback, ptr, TRUE);
                if (found_obj)
                        return found_obj;
        }
 
-       for (bigobj = los_object_list; bigobj; bigobj = bigobj->next) {
-               if (ptr >= bigobj->data && ptr < bigobj->data + bigobj->size)
-                       return bigobj->data;
-       }
+       found_obj = NULL;
+       mono_sgen_los_iterate_objects (find_object_for_ptr_callback, ptr);
+       if (found_obj)
+               return found_obj;
 
        /*
         * Very inefficient, but this is debugging code, supposed to
         * be called from gdb, so we don't care.
         */
        found_obj = NULL;
-       major_collector.iterate_objects (TRUE, TRUE, (IterateObjectCallbackFunc)find_object_for_ptr_callback, ptr);
+       major_collector.iterate_objects (TRUE, TRUE, find_object_for_ptr_callback, ptr);
        return found_obj;
 }
 
@@ -5829,7 +6328,7 @@ mono_gc_wbarrier_value_copy (gpointer dest, gpointer src, int count, MonoClass *
                sgen_card_table_mark_range ((mword)dest, size);
        } else {
                rs = REMEMBERED_SET;
-               if (ptr_in_nursery (dest) || ptr_on_stack (dest) || !klass->has_references) {
+               if (ptr_in_nursery (dest) || ptr_on_stack (dest) || !SGEN_CLASS_HAS_REFERENCES (klass)) {
                        UNLOCK_GC;
                        return;
                }
@@ -5918,11 +6417,18 @@ describe_ptr (char *ptr)
        MonoVTable *vtable;
        mword desc;
        int type;
+       char *start;
 
        if (ptr_in_nursery (ptr)) {
                printf ("Pointer inside nursery.\n");
        } else {
-               if (major_collector.ptr_is_in_non_pinned_space (ptr)) {
+               if (mono_sgen_ptr_is_in_los (ptr, &start)) {
+                       if (ptr == start)
+                               printf ("Pointer is the start of object %p in LOS space.\n", start);
+                       else
+                               printf ("Pointer is at offset 0x%x of object %p in LOS space.\n", (int)(ptr - start), start);
+                       ptr = start;
+               } else if (major_collector.ptr_is_in_non_pinned_space (ptr)) {
                        printf ("Pointer inside oldspace.\n");
                } else if (major_collector.obj_is_from_pinned_alloc (ptr)) {
                        printf ("Pointer is inside a pinned chunk.\n");
@@ -6120,8 +6626,6 @@ check_consistency_callback (char *start, size_t size, void *dummy)
 static void
 check_consistency (void)
 {
-       LOSObject *bigobj;
-
        // Need to add more checks
 
        missing_remsets = FALSE;
@@ -6131,14 +6635,11 @@ check_consistency (void)
        // Check that oldspace->newspace pointers are registered with the collector
        major_collector.iterate_objects (TRUE, TRUE, (IterateObjectCallbackFunc)check_consistency_callback, NULL);
 
-       for (bigobj = los_object_list; bigobj; bigobj = bigobj->next)
-               check_consistency_callback (bigobj->data, bigobj->size, NULL);
+       mono_sgen_los_iterate_objects ((IterateObjectCallbackFunc)check_consistency_callback, NULL);
 
        DEBUG (1, fprintf (gc_debug_file, "Heap consistency check done.\n"));
 
-#ifdef SGEN_BINARY_PROTOCOL
-       if (!binary_protocol_file)
-#endif
+       if (!binary_protocol_is_enabled ())
                g_assert (!missing_remsets);
 }
 
@@ -6159,12 +6660,8 @@ check_major_refs_callback (char *start, size_t size, void *dummy)
 static void
 check_major_refs (void)
 {
-       LOSObject *bigobj;
-
        major_collector.iterate_objects (TRUE, TRUE, (IterateObjectCallbackFunc)check_major_refs_callback, NULL);
-
-       for (bigobj = los_object_list; bigobj; bigobj = bigobj->next)
-               check_major_refs_callback (bigobj->data, bigobj->size, NULL);
+       mono_sgen_los_iterate_objects ((IterateObjectCallbackFunc)check_major_refs_callback, NULL);
 }
 
 /* Check that the reference is valid */
@@ -6204,16 +6701,18 @@ typedef struct {
        int count;
        int called;
        MonoObject *refs [REFS_SIZE];
+       uintptr_t offsets [REFS_SIZE];
 } HeapWalkInfo;
 
 #undef HANDLE_PTR
 #define HANDLE_PTR(ptr,obj)    do {    \
                if (*(ptr)) {   \
                        if (hwi->count == REFS_SIZE) {  \
-                               hwi->callback ((MonoObject*)start, mono_object_class (start), hwi->called? 0: size, hwi->count, hwi->refs, hwi->data);  \
+                               hwi->callback ((MonoObject*)start, mono_object_class (start), hwi->called? 0: size, hwi->count, hwi->refs, hwi->offsets, hwi->data);    \
                                hwi->count = 0; \
                                hwi->called = 1;        \
                        }       \
+                       hwi->offsets [hwi->count] = (char*)(ptr)-(char*)start;  \
                        hwi->refs [hwi->count++] = *(ptr);      \
                }       \
        } while (0)
@@ -6232,7 +6731,7 @@ walk_references (char *start, size_t size, void *data)
        hwi->count = 0;
        collect_references (hwi, start, size);
        if (hwi->count || !hwi->called)
-               hwi->callback ((MonoObject*)start, mono_object_class (start), hwi->called? 0: size, hwi->count, hwi->refs, hwi->data);
+               hwi->callback ((MonoObject*)start, mono_object_class (start), hwi->called? 0: size, hwi->count, hwi->refs, hwi->offsets, hwi->data);
 }
 
 /**
@@ -6244,6 +6743,8 @@ walk_references (char *start, size_t size, void *data)
  * This function can be used to iterate over all the live objects in the heap:
  * for each object, @callback is invoked, providing info about the object's
  * location in memory, its class, its size and the objects it references.
+ * For each referenced object it's offset from the object address is
+ * reported in the offsets array.
  * The object references may be buffered, so the callback may be invoked
  * multiple times for the same object: in all but the first call, the size
  * argument will be zero.
@@ -6256,19 +6757,17 @@ int
 mono_gc_walk_heap (int flags, MonoGCReferences callback, void *data)
 {
        HeapWalkInfo hwi;
-       LOSObject *bigobj;
 
        hwi.flags = flags;
        hwi.callback = callback;
        hwi.data = data;
 
        clear_nursery_fragments (nursery_next);
-       mono_sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, walk_references, &hwi);
+       mono_sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, walk_references, &hwi, FALSE);
 
        major_collector.iterate_objects (TRUE, TRUE, walk_references, &hwi);
+       mono_sgen_los_iterate_objects (walk_references, &hwi);
 
-       for (bigobj = los_object_list; bigobj; bigobj = bigobj->next)
-               walk_references (bigobj->data, bigobj->size, &hwi);
        return 0;
 }
 
@@ -6500,49 +6999,6 @@ mono_gc_is_gc_thread (void)
        return result;
 }
 
-/* Tries to extract a number from the passed string, taking in to account m, k
- * and g suffixes */
-gboolean
-mono_sgen_parse_environment_string_extract_number (const char *str, glong *out)
-{
-       char *endptr;
-       int len = strlen (str), shift = 0;
-       glong val;
-       gboolean is_suffix = FALSE;
-       char suffix;
-
-       switch (str [len - 1]) {
-               case 'g':
-               case 'G':
-                       shift += 10;
-               case 'm':
-               case 'M':
-                       shift += 10;
-               case 'k':
-               case 'K':
-                       shift += 10;
-                       is_suffix = TRUE;
-                       suffix = str [len - 1];
-                       break;
-       }
-
-       errno = 0;
-       val = strtol (str, &endptr, 10);
-
-       if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
-                       || (errno != 0 && val == 0) || (endptr == str))
-               return FALSE;
-
-       if (is_suffix) {
-               if (*(endptr + 1)) /* Invalid string. */
-                       return FALSE;
-               val <<= shift;
-       }
-
-       *out = val;
-       return TRUE;
-}
-
 void
 mono_gc_base_init (void)
 {
@@ -6550,10 +7006,8 @@ mono_gc_base_init (void)
        char **opts, **ptr;
        char *major_collector_opt = NULL;
        struct sigaction sinfo;
-
-#ifdef PLATFORM_ANDROID
-       g_assert_not_reached ();
-#endif
+       glong max_heap = 0;
+       int num_workers;
 
        /* the gc_initialized guard seems to imply this method is
           idempotent, but LOCK_INIT(gc_mutex) might not be.  It's
@@ -6566,10 +7020,11 @@ mono_gc_base_init (void)
                return;
        }
        pagesize = mono_pagesize ();
-       gc_debug_file = stderr;
+       gc_debug_file = stdout;
 
        LOCK_INIT (interruption_mutex);
        LOCK_INIT (global_remset_mutex);
+       LOCK_INIT (pin_queue_mutex);
 
        if ((env = getenv ("MONO_GC_PARAMS"))) {
                opts = g_strsplit (env, ",", -1);
@@ -6603,10 +7058,8 @@ mono_gc_base_init (void)
                mono_sgen_marksweep_fixed_init (&major_collector);
        } else if (!major_collector_opt || !strcmp (major_collector_opt, "marksweep-par")) {
                mono_sgen_marksweep_par_init (&major_collector);
-               workers_init (mono_cpu_count ());
        } else if (!major_collector_opt || !strcmp (major_collector_opt, "marksweep-fixed-par")) {
                mono_sgen_marksweep_fixed_par_init (&major_collector);
-               workers_init (mono_cpu_count ());
        } else if (!strcmp (major_collector_opt, "copying")) {
                mono_sgen_copying_init (&major_collector);
        } else {
@@ -6620,6 +7073,14 @@ mono_gc_base_init (void)
        use_cardtable = FALSE;
 #endif
 
+       num_workers = mono_cpu_count ();
+       g_assert (num_workers > 0);
+       if (num_workers > 16)
+               num_workers = 16;
+
+       /* Keep this the default for now */
+       conservative_stack_mark = TRUE;
+
        if (opts) {
                for (ptr = opts; *ptr; ++ptr) {
                        char *opt = *ptr;
@@ -6640,11 +7101,56 @@ mono_gc_base_init (void)
                                }
                                continue;
                        }
+                       if (g_str_has_prefix (opt, "max-heap-size=")) {
+                               opt = strchr (opt, '=') + 1;
+                               if (*opt && mono_gc_parse_environment_string_extract_number (opt, &max_heap)) {
+                                       if ((max_heap & (mono_pagesize () - 1))) {
+                                               fprintf (stderr, "max-heap-size size must be a multiple of %d.\n", mono_pagesize ());
+                                               exit (1);
+                                       }
+                               } else {
+                                       fprintf (stderr, "max-heap-size must be an integer.\n");
+                                       exit (1);
+                               }
+                               continue;
+                       }
+                       if (g_str_has_prefix (opt, "workers=")) {
+                               long val;
+                               char *endptr;
+                               if (!major_collector.is_parallel) {
+                                       fprintf (stderr, "The workers= option can only be used for parallel collectors.");
+                                       exit (1);
+                               }
+                               opt = strchr (opt, '=') + 1;
+                               val = strtol (opt, &endptr, 10);
+                               if (!*opt || *endptr) {
+                                       fprintf (stderr, "Cannot parse the workers= option value.");
+                                       exit (1);
+                               }
+                               if (val <= 0 || val > 16) {
+                                       fprintf (stderr, "The number of workers must be in the range 1 to 16.");
+                                       exit (1);
+                               }
+                               num_workers = (int)val;
+                               continue;
+                       }
+                       if (g_str_has_prefix (opt, "stack-mark=")) {
+                               opt = strchr (opt, '=') + 1;
+                               if (!strcmp (opt, "precise")) {
+                                       conservative_stack_mark = FALSE;
+                               } else if (!strcmp (opt, "conservative")) {
+                                       conservative_stack_mark = TRUE;
+                               } else {
+                                       fprintf (stderr, "Invalid value '%s' for stack-mark= option, possible values are: 'precise', 'conservative'.\n", opt);
+                                       exit (1);
+                               }
+                               continue;
+                       }
 #ifdef USER_CONFIG
                        if (g_str_has_prefix (opt, "nursery-size=")) {
                                long val;
                                opt = strchr (opt, '=') + 1;
-                               if (*opt && mono_sgen_parse_environment_string_extract_number (opt, &val)) {
+                               if (*opt && mono_gc_parse_environment_string_extract_number (opt, &val)) {
                                        default_nursery_size = val;
 #ifdef SGEN_ALIGN_NURSERY
                                        if ((val & (val - 1))) {
@@ -6665,9 +7171,11 @@ mono_gc_base_init (void)
 #endif
                        if (!(major_collector.handle_gc_param && major_collector.handle_gc_param (opt))) {
                                fprintf (stderr, "MONO_GC_PARAMS must be a comma-delimited list of one or more of the following:\n");
+                               fprintf (stderr, "  max-heap-size=N (where N is an integer, possibly with a k, m or a g suffix)\n");
                                fprintf (stderr, "  nursery-size=N (where N is an integer, possibly with a k, m or a g suffix)\n");
                                fprintf (stderr, "  major=COLLECTOR (where COLLECTOR is `marksweep', `marksweep-par' or `copying')\n");
                                fprintf (stderr, "  wbarrier=WBARRIER (where WBARRIER is `remset' or `cardtable')\n");
+                               fprintf (stderr, "  stack-mark=MARK-METHOD (where MARK-METHOD is 'precise' or 'conservative')\n");
                                if (major_collector.print_gc_param_usage)
                                        major_collector.print_gc_param_usage ();
                                exit (1);
@@ -6676,11 +7184,15 @@ mono_gc_base_init (void)
                g_strfreev (opts);
        }
 
+       if (major_collector.is_parallel)
+               workers_init (num_workers);
+
        if (major_collector_opt)
                g_free (major_collector_opt);
 
        nursery_size = DEFAULT_NURSERY_SIZE;
        minor_collection_allowance = MIN_MINOR_COLLECTION_ALLOWANCE;
+       init_heap_size_limits (max_heap);
 
        alloc_nursery ();
 
@@ -6701,7 +7213,10 @@ mono_gc_base_init (void)
                                        g_free (rf);
                                }
                        } else if (!strcmp (opt, "collect-before-allocs")) {
-                               collect_before_allocs = TRUE;
+                               collect_before_allocs = 1;
+                       } else if (g_str_has_prefix (opt, "collect-before-allocs=")) {
+                               char *arg = strchr (opt, '=') + 1;
+                               collect_before_allocs = atoi (arg);
                        } else if (!strcmp (opt, "check-at-minor-collections")) {
                                consistency_check_at_minor_collection = TRUE;
                                nursery_clear_policy = CLEAR_AT_GC;
@@ -6709,8 +7224,8 @@ mono_gc_base_init (void)
                                xdomain_checks = TRUE;
                        } else if (!strcmp (opt, "clear-at-gc")) {
                                nursery_clear_policy = CLEAR_AT_GC;
-                       } else if (!strcmp (opt, "conservative-stack-mark")) {
-                               conservative_stack_mark = TRUE;
+                       } else if (!strcmp (opt, "clear-nursery-at-gc")) {
+                               nursery_clear_policy = CLEAR_AT_GC;
                        } else if (!strcmp (opt, "check-scan-starts")) {
                                do_scan_starts_check = TRUE;
                        } else if (g_str_has_prefix (opt, "heap-dump=")) {
@@ -6722,18 +7237,21 @@ mono_gc_base_init (void)
 #ifdef SGEN_BINARY_PROTOCOL
                        } else if (g_str_has_prefix (opt, "binary-protocol=")) {
                                char *filename = strchr (opt, '=') + 1;
-                               binary_protocol_file = fopen (filename, "w");
+                               binary_protocol_init (filename);
 #endif
                        } else {
                                fprintf (stderr, "Invalid format for the MONO_GC_DEBUG env variable: '%s'\n", env);
                                fprintf (stderr, "The format is: MONO_GC_DEBUG=[l[:filename]|<option>]+ where l is a debug level 0-9.\n");
-                               fprintf (stderr, "Valid options are: collect-before-allocs, check-at-minor-collections, xdomain-checks, clear-at-gc.\n");
+                               fprintf (stderr, "Valid options are: collect-before-allocs[=<n>], check-at-minor-collections, xdomain-checks, clear-at-gc.\n");
                                exit (1);
                        }
                }
                g_strfreev (opts);
        }
 
+       if (major_collector.post_param_init)
+               major_collector.post_param_init ();
+
        suspend_ack_semaphore_ptr = &suspend_ack_semaphore;
        MONO_SEM_INIT (&suspend_ack_semaphore, 0);
 
@@ -6789,6 +7307,12 @@ enum {
        mono_mb_emit_i4 ((mb), (offset));               \
        } while (0)
 #else
+
+/* 
+ * CEE_MONO_TLS requires the tls offset, not the key, so the code below only works on darwin,
+ * where the two are the same.
+ */
+#ifdef __APPLE__
 #define EMIT_TLS_ACCESS(mb,member,dummy)       do {    \
        mono_mb_emit_byte ((mb), MONO_CUSTOM_PREFIX);   \
        mono_mb_emit_byte ((mb), CEE_MONO_TLS);         \
@@ -6797,6 +7321,10 @@ enum {
        mono_mb_emit_byte ((mb), CEE_ADD);              \
        mono_mb_emit_byte ((mb), CEE_LDIND_I);          \
        } while (0)
+#else
+#define EMIT_TLS_ACCESS(mb,member,dummy)       do { g_error ("sgen is not supported when using --with-tls=pthread.\n"); } while (0)
+#endif
+
 #endif
 
 #ifdef MANAGED_ALLOCATION
@@ -7138,7 +7666,7 @@ mono_gc_get_managed_array_allocator (MonoVTable *vtable, int rank)
                return NULL;
        if (collect_before_allocs)
                return NULL;
-       g_assert (!klass->has_finalize && !klass->marshalbyref);
+       g_assert (!mono_class_has_finalizer (klass) && !klass->marshalbyref);
 
        return mono_gc_get_managed_allocator_by_type (ATYPE_VECTOR);
 #else
@@ -7406,4 +7934,17 @@ mono_sgen_debug_printf (int level, const char *format, ...)
        va_end (ap);
 }
 
+FILE*
+mono_sgen_get_logfile (void)
+{
+       return gc_debug_file;
+}
+
+#ifdef HOST_WIN32
+BOOL APIENTRY mono_gc_dllmain (HMODULE module_handle, DWORD reason, LPVOID reserved)
+{
+       return TRUE;
+}
+#endif
+
 #endif /* HAVE_SGEN_GC */