Merge pull request #900 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mono / metadata / sgen-nursery-allocator.c
index 8833b316c9f9828b6cd8d50c11e13b2d2484d609..7abd0387fcfe08df948ec352d85ba6c5eab738c7 100644 (file)
@@ -1,31 +1,24 @@
 /*
  * sgen-nursery-allocator.c: Nursery allocation code.
  *
- *
  * Copyright 2009-2010 Novell, Inc.
  *           2011 Rodrigo Kumpera
  * 
  * Copyright 2011 Xamarin Inc  (http://www.xamarin.com)
+ * Copyright (C) 2012 Xamarin Inc
  *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License 2.0 as published by the Free Software Foundation;
  *
- * 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.
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License 2.0 along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 /*
@@ -77,6 +70,7 @@
 #include "metadata/sgen-protocol.h"
 #include "metadata/sgen-archdep.h"
 #include "metadata/sgen-bridge.h"
+#include "metadata/sgen-memory-governor.h"
 #include "metadata/mono-gc.h"
 #include "metadata/method-builder.h"
 #include "metadata/profiler-private.h"
 #include "utils/mono-proclib.h"
 #include "utils/mono-threads.h"
 
-/*
-The nursery is logically divided into 3 spaces: Allocator space and two Survivor spaces.
-
-Objects are born (allocated by the mutator) in the Allocator Space.
-
-The Survivor spaces are divided in a copying collector style From and To spaces.
-The hole of each space switch on each collection.
-
-On each collection we process objects from the nursery this way:
-Objects from the Allocator Space are evacuated into the To Space.
-Objects from the Survivor From Space are evacuated into the old generation.
-
-
-The nursery is physically divided in two parts, set by the promotion barrier.
-
-The Allocator Space takes the botton part of the nursery.
-
-The Survivor spaces are intermingled in the top part of the nursery. It's done
-this way since the required size for the To Space depends on the survivor rate
-of objects from the Allocator Space. 
-
-During a collection when the object scan function see a nursery object it must
-determine if the object needs to be evacuated or left in place. Originally, this
-check was done by checking is a forwarding pointer is installed, but now an object
-can be in the To Space, it won't have a forwarding pointer and it must be left in place.
-
-In order to solve that we classify nursery memory been either in the From Space or in
-the To Space. Since the Allocator Space has the same behavior as the Survivor From Space
-they are unified for this purpoise - a bit confusing at first.
-
-This from/to classification is done on a larger granule than object to make the check efficient
-and, due to that, we must make sure that all fragemnts used to allocate memory from the To Space
-are naturally aligned in both ends to that granule to avoid wronly classifying a From Space object.
-
-TODO:
--The promotion barrier is statically defined to 50% of the nursery, it should be dinamically adjusted based
-on survival rates;
--Objects are aged just one collection, we need to implement multiple cycle aging;
--We apply the same promotion policy to all objects, finalizable ones should age longer in the nursery;
--We apply the same promotion policy to all stages of a collection, maybe we should promote more aggressively
-objects from non-stack roots, specially those found in the remembered set;
--Make the new behavior runtime selectable;
--Make the new behavior have a low overhead when disabled;
--Make all new exported functions inlineable in other modules;
--Create specialized copy & scan functions for nursery collections;
--Decide if this is the right place for this code;
--Fix our major collection trigger to happen before we do a minor GC and collect the nursery only once.
-*/
-static char *promotion_barrier;
-
-typedef struct _Fragment Fragment;
-
-struct _Fragment {
-       Fragment *next;
-       char *fragment_start;
-       char *fragment_next; /* the current soft limit for allocation */
-       char *fragment_end;
-       Fragment *next_in_order; /* We use a different entry for all active fragments so we can avoid SMR. */
-};
-
-typedef struct {
-       Fragment *alloc_head; /* List head to be used when allocating memory. Walk with fragment_next. */
-       Fragment *region_head; /* List head of the region used by this allocator. Walk with next_in_order. */
-} FragmentAllocator;
-
 /* Enable it so nursery allocation diagnostic data is collected */
 //#define NALLOC_DEBUG 1
 
 /* The mutator allocs from here. */
-static FragmentAllocator mutator_allocator;
-
-/* The collector allocs from here. */
-static FragmentAllocator collector_allocator;
+SgenFragmentAllocator mutator_allocator;
 
 /* freeelist of fragment structures */
-static Fragment *fragment_freelist = NULL;
+static SgenFragment *fragment_freelist = NULL;
 
 /* Allocator cursors */
 static char *nursery_last_pinned_end = NULL;
@@ -181,8 +107,8 @@ int sgen_nursery_bits = 22;
 #endif
 #endif
 
-
-static void sgen_clear_range (char *start, char *end);
+char *sgen_space_bitmap MONO_INTERNAL;
+int sgen_space_bitmap_size MONO_INTERNAL;
 
 #ifdef HEAVY_STATISTICS
 
@@ -226,6 +152,8 @@ static AllocRecord *alloc_records;
 static volatile int next_record;
 static volatile int alloc_count;
 
+void dump_alloc_records (void);
+void verify_alloc_records (void);
 
 static const char*
 get_reason_name (AllocRecord *rec)
@@ -274,7 +202,7 @@ void
 dump_alloc_records (void)
 {
        int i;
-       qsort (alloc_records, next_record, sizeof (AllocRecord), comp_alloc_record);
+       sgen_qsort (alloc_records, next_record, sizeof (AllocRecord), comp_alloc_record);
 
        printf ("------------------------------------DUMP RECORDS----------------------------\n");
        for (i = 0; i < next_record; ++i) {
@@ -292,7 +220,7 @@ verify_alloc_records (void)
        int max_hole = 0;
        AllocRecord *prev = NULL;
 
-       qsort (alloc_records, next_record, sizeof (AllocRecord), comp_alloc_record);
+       sgen_qsort (alloc_records, next_record, sizeof (AllocRecord), comp_alloc_record);
        printf ("------------------------------------DUMP RECORDS- %d %d---------------------------\n", next_record, alloc_count);
        for (i = 0; i < next_record; ++i) {
                AllocRecord *rec = alloc_records + i;
@@ -336,10 +264,10 @@ get_mark (gpointer n)
 }
 
 /*MUST be called with world stopped*/
-static Fragment*
-alloc_fragment (void)
+SgenFragment*
+sgen_fragment_allocator_alloc (void)
 {
-       Fragment *frag = fragment_freelist;
+       SgenFragment *frag = fragment_freelist;
        if (frag) {
                fragment_freelist = frag->next_in_order;
                frag->next = frag->next_in_order = NULL;
@@ -350,12 +278,12 @@ alloc_fragment (void)
        return frag;
 }
 
-static void
-add_fragment (FragmentAllocator *allocator, char *start, char *end)
+void
+sgen_fragment_allocator_add (SgenFragmentAllocator *allocator, char *start, char *end)
 {
-       Fragment *fragment;
+       SgenFragment *fragment;
 
-       fragment = alloc_fragment ();
+       fragment = sgen_fragment_allocator_alloc ();
        fragment->fragment_start = start;
        fragment->fragment_next = start;
        fragment->fragment_end = end;
@@ -365,10 +293,10 @@ add_fragment (FragmentAllocator *allocator, char *start, char *end)
        g_assert (fragment->fragment_end > fragment->fragment_start);
 }
 
-static void
-release_fragment_list (FragmentAllocator *allocator)
+void
+sgen_fragment_allocator_release (SgenFragmentAllocator *allocator)
 {
-       Fragment *last = allocator->region_head;
+       SgenFragment *last = allocator->region_head;
        if (!last)
                return;
 
@@ -380,11 +308,11 @@ release_fragment_list (FragmentAllocator *allocator)
        allocator->alloc_head = allocator->region_head = NULL;
 }
 
-static Fragment**
-find_previous_pointer_fragment (FragmentAllocator *allocator, Fragment *frag)
+static SgenFragment**
+find_previous_pointer_fragment (SgenFragmentAllocator *allocator, SgenFragment *frag)
 {
-       Fragment **prev;
-       Fragment *cur, *next;
+       SgenFragment **prev;
+       SgenFragment *cur, *next;
 #ifdef NALLOC_DEBUG
        int count = 0;
 #endif
@@ -431,7 +359,7 @@ try_again:
 }
 
 static gboolean
-claim_remaining_size (Fragment *frag, char *alloc_end)
+claim_remaining_size (SgenFragment *frag, char *alloc_end)
 {
        /* All space used, nothing to claim. */
        if (frag->fragment_end <= alloc_end)
@@ -442,7 +370,7 @@ claim_remaining_size (Fragment *frag, char *alloc_end)
 }
 
 static void*
-par_alloc_from_fragment (FragmentAllocator *allocator, Fragment *frag, size_t size)
+par_alloc_from_fragment (SgenFragmentAllocator *allocator, SgenFragment *frag, size_t size)
 {
        char *p = frag->fragment_next;
        char *end = p + size;
@@ -457,7 +385,7 @@ par_alloc_from_fragment (FragmentAllocator *allocator, Fragment *frag, size_t si
                return NULL;
 
        if (frag->fragment_end - end < SGEN_MAX_NURSERY_WASTE) {
-               Fragment *next, **prev_ptr;
+               SgenFragment *next, **prev_ptr;
                
                /*
                 * Before we clean the remaining nursery, we must claim the remaining space
@@ -508,7 +436,7 @@ par_alloc_from_fragment (FragmentAllocator *allocator, Fragment *frag, size_t si
 }
 
 static void*
-serial_alloc_from_fragment (Fragment **previous, Fragment *frag, size_t size)
+serial_alloc_from_fragment (SgenFragment **previous, SgenFragment *frag, size_t size)
 {
        char *p = frag->fragment_next;
        char *end = p + size;
@@ -530,10 +458,10 @@ serial_alloc_from_fragment (Fragment **previous, Fragment *frag, size_t size)
        return p;
 }
 
-static void*
-par_alloc (FragmentAllocator *allocator, size_t size)
+void*
+sgen_fragment_allocator_par_alloc (SgenFragmentAllocator *allocator, size_t size)
 {
-       Fragment *frag;
+       SgenFragment *frag;
 
 #ifdef NALLOC_DEBUG
        InterlockedIncrement (&alloc_count);
@@ -558,11 +486,11 @@ restart:
        return NULL;
 }
 
-static void*
-serial_alloc (FragmentAllocator *allocator, size_t size)
+void*
+sgen_fragment_allocator_serial_alloc (SgenFragmentAllocator *allocator, size_t size)
 {
-       Fragment *frag;
-       Fragment **previous;
+       SgenFragment *frag;
+       SgenFragment **previous;
 #ifdef NALLOC_DEBUG
        InterlockedIncrement (&alloc_count);
 #endif
@@ -585,12 +513,66 @@ serial_alloc (FragmentAllocator *allocator, size_t size)
        return NULL;
 }
 
-static void*
-par_range_alloc (FragmentAllocator *allocator, size_t desired_size, size_t minimum_size, int *out_alloc_size)
+void*
+sgen_fragment_allocator_serial_range_alloc (SgenFragmentAllocator *allocator, size_t desired_size, size_t minimum_size, size_t *out_alloc_size)
+{
+       SgenFragment *frag, **previous, *min_frag = NULL, **prev_min_frag = NULL;
+       size_t current_minimum = minimum_size;
+
+#ifdef NALLOC_DEBUG
+       InterlockedIncrement (&alloc_count);
+#endif
+
+       previous = &allocator->alloc_head;
+
+       for (frag = *previous; frag; frag = *previous) {
+               size_t frag_size = frag->fragment_end - frag->fragment_next;
+
+               HEAVY_STAT (InterlockedIncrement (&stat_alloc_range_iterations));
+
+               if (desired_size <= frag_size) {
+                       void *p;
+                       *out_alloc_size = desired_size;
+
+                       p = serial_alloc_from_fragment (previous, frag, desired_size);
+#ifdef NALLOC_DEBUG
+                       add_alloc_record (p, desired_size, RANGE_ALLOC);
+#endif
+                       return p;
+               }
+               if (current_minimum <= frag_size) {
+                       min_frag = frag;
+                       prev_min_frag = previous;
+                       current_minimum = frag_size;
+               }
+               previous = &frag->next;
+       }
+
+       if (min_frag) {
+               void *p;
+               size_t frag_size = min_frag->fragment_end - min_frag->fragment_next;
+               *out_alloc_size = frag_size;
+
+               p = serial_alloc_from_fragment (prev_min_frag, min_frag, frag_size);
+
+#ifdef NALLOC_DEBUG
+               add_alloc_record (p, frag_size, RANGE_ALLOC);
+#endif
+               return p;
+       }
+
+       return NULL;
+}
+
+void*
+sgen_fragment_allocator_par_range_alloc (SgenFragmentAllocator *allocator, size_t desired_size, size_t minimum_size, size_t *out_alloc_size)
 {
-       Fragment *frag, *min_frag;
+       SgenFragment *frag, *min_frag;
+       size_t current_minimum;
+
 restart:
        min_frag = NULL;
+       current_minimum = minimum_size;
 
 #ifdef NALLOC_DEBUG
        InterlockedIncrement (&alloc_count);
@@ -615,8 +597,10 @@ restart:
 #endif
                        return p;
                }
-               if (minimum_size <= frag_size)
+               if (current_minimum <= frag_size) {
                        min_frag = frag;
+                       current_minimum = frag_size;
+               }
        }
 
        /* The second fragment_next read should be ordered in respect to the first code block */
@@ -649,13 +633,13 @@ restart:
        return NULL;
 }
 
-static void
-clear_allocator_fragments (FragmentAllocator *allocator)
+void
+sgen_clear_allocator_fragments (SgenFragmentAllocator *allocator)
 {
-       Fragment *frag;
+       SgenFragment *frag;
 
        for (frag = unmask (allocator->alloc_head); frag; frag = unmask (frag->next)) {
-               DEBUG (4, fprintf (gc_debug_file, "Clear nursery frag %p-%p\n", frag->fragment_next, frag->fragment_end));
+               SGEN_LOG (4, "Clear nursery frag %p-%p", frag->fragment_next, frag->fragment_end);
                sgen_clear_range (frag->fragment_next, frag->fragment_end);
 #ifdef NALLOC_DEBUG
                add_alloc_record (frag->fragment_next, frag->fragment_end - frag->fragment_next, CLEAR_NURSERY_FRAGS);
@@ -668,17 +652,29 @@ void
 sgen_clear_nursery_fragments (void)
 {
        if (sgen_get_nursery_clear_policy () == CLEAR_AT_TLAB_CREATION) {
-               clear_allocator_fragments (&mutator_allocator);
-               clear_allocator_fragments (&collector_allocator);
+               sgen_clear_allocator_fragments (&mutator_allocator);
+               sgen_minor_collector.clear_fragments ();
        }
 }
 
-static void
+/*
+ * Mark a given range of memory as invalid.
+ *
+ * This can be done either by zeroing memory or by placing
+ * a phony byte[] array. This keeps the heap forward walkable.
+ *
+ * This function ignores calls with a zero range, even if
+ * both start and end are NULL.
+ */
+void
 sgen_clear_range (char *start, char *end)
 {
        MonoArray *o;
        size_t size = end - start;
 
+       if ((start && !end) || (start > end))
+               g_error ("Invalid range [%p %p]", start, end);
+
        if (size < sizeof (MonoArray)) {
                memset (start, 0, size);
                return;
@@ -697,8 +693,8 @@ sgen_clear_range (char *start, char *end)
 void
 sgen_nursery_allocator_prepare_for_pinning (void)
 {
-       clear_allocator_fragments (&mutator_allocator);
-       clear_allocator_fragments (&collector_allocator);
+       sgen_clear_allocator_fragments (&mutator_allocator);
+       sgen_minor_collector.clear_fragments ();
 }
 
 static mword fragment_total = 0;
@@ -708,10 +704,11 @@ static mword fragment_total = 0;
  * allocation.
  */
 static void
-add_nursery_frag (FragmentAllocator *allocator, size_t frag_size, char* frag_start, char* frag_end)
+add_nursery_frag (SgenFragmentAllocator *allocator, size_t frag_size, char* frag_start, char* frag_end)
 {
-       DEBUG (4, fprintf (gc_debug_file, "Found empty fragment: %p-%p, size: %zd\n", frag_start, frag_end, frag_size));
+       SGEN_LOG (4, "Found empty fragment: %p-%p, size: %zd", frag_start, frag_end, frag_size);
        binary_protocol_empty (frag_start, frag_size);
+       MONO_GC_NURSERY_SWEPT ((mword)frag_start, frag_end - frag_start);
        /* Not worth dealing with smaller fragments: need to tune */
        if (frag_size >= SGEN_MAX_NURSERY_WASTE) {
                /* memsetting just the first chunk start is bound to provide better cache locality */
@@ -723,7 +720,7 @@ add_nursery_frag (FragmentAllocator *allocator, size_t frag_size, char* frag_sta
                printf ("\tfragment [%p %p] size %zd\n", frag_start, frag_end, frag_size);
                */
 #endif
-               add_fragment (allocator, frag_start, frag_end);
+               sgen_fragment_allocator_add (allocator, frag_start, frag_end);
                fragment_total += frag_size;
        } else {
                /* Clear unused fragments, pinning depends on this */
@@ -733,11 +730,11 @@ add_nursery_frag (FragmentAllocator *allocator, size_t frag_size, char* frag_sta
 }
 
 static void
-fragment_list_reverse (FragmentAllocator *allocator)
+fragment_list_reverse (SgenFragmentAllocator *allocator)
 {
-       Fragment *prev = NULL, *list = allocator->region_head;
+       SgenFragment *prev = NULL, *list = allocator->region_head;
        while (list) {
-               Fragment *next = list->next;
+               SgenFragment *next = list->next;
                list->next = prev;
                list->next_in_order = prev;
                prev = list;
@@ -747,76 +744,45 @@ fragment_list_reverse (FragmentAllocator *allocator)
        allocator->region_head = allocator->alloc_head = prev;
 }
 
-static void
-fragment_list_split (FragmentAllocator *allocator)
-{
-       Fragment *prev = NULL, *list = allocator->region_head;
-
-       while (list) {
-               if (list->fragment_end > promotion_barrier) {
-                       if (list->fragment_start < promotion_barrier) {
-                               Fragment *res = alloc_fragment ();
-
-                               res->fragment_start = promotion_barrier;
-                               res->fragment_next = promotion_barrier;
-                               res->fragment_end = list->fragment_end;
-                               res->next = list->next;
-                               res->next_in_order = list->next_in_order;
-                               g_assert (res->fragment_end > res->fragment_start);
-
-                               list->fragment_end = promotion_barrier;
-                               list->next = list->next_in_order = NULL;
-
-                               allocator->region_head = allocator->alloc_head = res;
-                               return;
-                       } else {
-                               if (prev)
-                                       prev->next = prev->next_in_order = NULL;
-                               allocator->region_head = allocator->alloc_head = list;
-                               return;
-                       }
-               }
-               prev = list;
-               list = list->next;
-       }
-       allocator->region_head = allocator->alloc_head = NULL;
-}
-
-
 mword
-sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, int num_entries)
+sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, int num_entries, SgenGrayQueue *unpin_queue)
 {
        char *frag_start, *frag_end;
        size_t frag_size;
        int i = 0;
-       Fragment *frags_ranges;
+       SgenFragment *frags_ranges;
 
 #ifdef NALLOC_DEBUG
        reset_alloc_records ();
 #endif
+       /*The mutator fragments are done. We no longer need them. */
+       sgen_fragment_allocator_release (&mutator_allocator);
 
-       release_fragment_list (&mutator_allocator);
-
-       frags_ranges = collector_allocator.region_head;
        frag_start = sgen_nursery_start;
        fragment_total = 0;
 
+       /* The current nursery might give us a fragment list to exclude [start, next[*/
+       frags_ranges = sgen_minor_collector.build_fragments_get_exclude_head ();
+
        /* clear scan starts */
        memset (nursery_section->scan_starts, 0, nursery_section->num_scan_start * sizeof (gpointer));
+
        while (i < num_entries || frags_ranges) {
                char *addr0, *addr1;
                size_t size;
-               Fragment *last_frag = NULL;
+               SgenFragment *last_frag = NULL;
 
                addr0 = addr1 = sgen_nursery_end;
                if (i < num_entries)
                        addr0 = start [i];
-               if (frags_ranges) {
+               if (frags_ranges)
                        addr1 = frags_ranges->fragment_start;
-               }
 
                if (addr0 < addr1) {
-                       SGEN_UNPIN_OBJECT (addr0);
+                       if (unpin_queue)
+                               GRAY_OBJECT_ENQUEUE (unpin_queue, addr0);
+                       else
+                               SGEN_UNPIN_OBJECT (addr0);
                        sgen_set_nursery_scan_start (addr0);
                        frag_end = addr0;
                        size = SGEN_ALIGN_UP (sgen_safe_object_get_size ((MonoObject*)addr0));
@@ -851,20 +817,19 @@ sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, int n
        if (frag_size)
                add_nursery_frag (&mutator_allocator, frag_size, frag_start, frag_end);
 
-       /* Now it's safe to release collector fragments. */
-       release_fragment_list (&collector_allocator);
+       /* Now it's safe to release the fragments exclude list. */
+       sgen_minor_collector.build_fragments_release_exclude_head ();
 
-       /* First we reorder the fragment list to be in ascending address order. */
+       /* First we reorder the fragment list to be in ascending address order. This makes H/W prefetchers happier. */
        fragment_list_reverse (&mutator_allocator);
 
-       /* We split the fragment list based on the promotion barrier. */
-       collector_allocator = mutator_allocator;
-       fragment_list_split (&collector_allocator);
+       /*The collector might want to do something with the final nursery fragment list.*/
+       sgen_minor_collector.build_fragments_finish (&mutator_allocator);
 
        if (!unmask (mutator_allocator.alloc_head)) {
-               DEBUG (1, fprintf (gc_debug_file, "Nursery fully pinned (%d)\n", num_entries));
+               SGEN_LOG (1, "Nursery fully pinned (%d)", num_entries);
                for (i = 0; i < num_entries; ++i) {
-                       DEBUG (3, fprintf (gc_debug_file, "Bastard pinning obj %p (%s), size: %d\n", start [i], sgen_safe_name (start [i]), sgen_safe_object_get_size (start [i])));
+                       SGEN_LOG (3, "Bastard pinning obj %p (%s), size: %d", start [i], sgen_safe_name (start [i]), sgen_safe_object_get_size (start [i]));
                }
        }
        return fragment_total;
@@ -887,7 +852,11 @@ sgen_nursery_retire_region (void *address, ptrdiff_t size)
 gboolean
 sgen_can_alloc_size (size_t size)
 {
-       Fragment *frag;
+       SgenFragment *frag;
+
+       if (!SGEN_CAN_ALIGN_UP (size))
+               return FALSE;
+
        size = SGEN_ALIGN_UP (size);
 
        for (frag = unmask (mutator_allocator.alloc_head); frag; frag = unmask (frag->next)) {
@@ -900,22 +869,24 @@ sgen_can_alloc_size (size_t size)
 void*
 sgen_nursery_alloc (size_t size)
 {
-       DEBUG (4, fprintf (gc_debug_file, "Searching nursery for size: %zd\n", size));
+       SGEN_ASSERT (1, size >= sizeof (MonoObject) && size <= SGEN_MAX_SMALL_OBJ_SIZE, "Invalid nursery object size");
+
+       SGEN_LOG (4, "Searching nursery for size: %zd", size);
        size = SGEN_ALIGN_UP (size);
 
        HEAVY_STAT (InterlockedIncrement (&stat_nursery_alloc_requests));
 
-       return par_alloc (&mutator_allocator, size);
+       return sgen_fragment_allocator_par_alloc (&mutator_allocator, size);
 }
 
 void*
-sgen_nursery_alloc_range (size_t desired_size, size_t minimum_size, int *out_alloc_size)
+sgen_nursery_alloc_range (size_t desired_size, size_t minimum_size, size_t *out_alloc_size)
 {
-       DEBUG (4, fprintf (gc_debug_file, "Searching for byte range desired size: %zd minimum size %zd\n", desired_size, minimum_size));
+       SGEN_LOG (4, "Searching for byte range desired size: %zd minimum size %zd", desired_size, minimum_size);
 
        HEAVY_STAT (InterlockedIncrement (&stat_nursery_alloc_range_requests));
 
-       return par_range_alloc (&mutator_allocator, desired_size, minimum_size, out_alloc_size);
+       return sgen_fragment_allocator_par_range_alloc (&mutator_allocator, desired_size, minimum_size, out_alloc_size);
 }
 
 /*** Initialization ***/
@@ -943,194 +914,35 @@ sgen_nursery_allocator_init_heavy_stats (void)
 void
 sgen_init_nursery_allocator (void)
 {
-       sgen_register_fixed_internal_mem_type (INTERNAL_MEM_FRAGMENT, sizeof (Fragment));
+       sgen_register_fixed_internal_mem_type (INTERNAL_MEM_FRAGMENT, sizeof (SgenFragment));
 #ifdef NALLOC_DEBUG
-       alloc_records = sgen_alloc_os_memory (sizeof (AllocRecord) * ALLOC_RECORD_COUNT, TRUE);
+       alloc_records = sgen_alloc_os_memory (sizeof (AllocRecord) * ALLOC_RECORD_COUNT, SGEN_ALLOC_INTERNAL | SGEN_ALLOC_ACTIVATE, "debugging memory");
 #endif
 }
 
-char*
-sgen_alloc_for_promotion (char *obj, size_t objsize, gboolean has_references)
-{
-       char *p;
-
-       if (objsize > SGEN_MAX_SMALL_OBJ_SIZE)
-               g_error ("asked to allocate object size %d\n", objsize);
-
-       /*This one will be internally promoted. */
-       if (obj >= sgen_nursery_start && obj < promotion_barrier) {
-               p = serial_alloc (&collector_allocator, objsize);
-
-               /* Have we failed to promote to the nursery, lets just evacuate it to old gen. */
-               if (!p)
-                       p = sgen_get_major_collector()->alloc_object (objsize, has_references);
-       } else {
-               p = sgen_get_major_collector()->alloc_object (objsize, has_references);
-       }
-
-       return p;
-}
-
-char*
-sgen_par_alloc_for_promotion (char *obj, size_t objsize, gboolean has_references)
-{
-       char *p;
-
-       /*This one will be internally promoted. */
-       if (obj >= sgen_nursery_start && obj < promotion_barrier) {
-               p = par_alloc (&collector_allocator, objsize);
-
-               /* Have we failed to promote to the nursery, lets just evacuate it to old gen. */
-               if (!p)
-                       p = sgen_get_major_collector()->par_alloc_object (objsize, has_references);                     
-       } else {
-               p = sgen_get_major_collector()->par_alloc_object (objsize, has_references);
-       }
-
-       return p;
-}
-
-/*
-This is a space/speed compromise as we need to make sure the from/to space check is both O(1)
-and only hit cache hot memory. On a 4Mb nursery it requires 1024 bytes, or 3% of your average
-L1 cache. On small configs with a 512kb nursery, this goes to 0.4%.
-
-Experimental results on how much space we waste with a 4Mb nursery:
-
-Note that the wastage applies to the half nursery, or 2Mb:
-
-Test 1 (compiling corlib):
-9: avg: 3.1k
-8: avg: 1.6k
-
-*/
-#define SPACE_GRANULE_BITS 9
-#define SPACE_GRANULE_IN_BYTES (1 << SPACE_GRANULE_BITS)
-
-static char *space_bitmap;
-static int space_bitmap_size;
-
-/*FIXME Move this to a separate header. */
-#define _toi(ptr) ((size_t)ptr)
-#define make_ptr_mask(bits) ((1 << bits) - 1)
-#define align_down(ptr, bits) ((void*)(_toi(ptr) & ~make_ptr_mask (bits)))
-#define align_up(ptr, bits) ((void*) ((_toi(ptr) + make_ptr_mask (bits)) & ~make_ptr_mask (bits)))
-
-gboolean
-sgen_nursery_is_object_alive (char *obj)
-{
-       g_assert (sgen_ptr_in_nursery (obj));
-
-       if (sgen_nursery_is_to_space (obj))
-               return TRUE;
-
-       if (SGEN_OBJECT_IS_PINNED (obj) || SGEN_OBJECT_IS_FORWARDED (obj))
-               return TRUE;
-
-       return FALSE;
-}
-
-gboolean
-sgen_nursery_is_from_space (char *pos)
-{
-       int idx = (pos - sgen_nursery_start) >> SPACE_GRANULE_BITS;
-       int byte = idx / 8;
-       int bit = idx & 0x7;
-       g_assert (sgen_ptr_in_nursery (pos));
-
-       return (space_bitmap [byte] & (1 << bit)) == 0;
-}
-
-gboolean
-sgen_nursery_is_to_space (char *pos)
-{
-       int idx = (pos - sgen_nursery_start) >> SPACE_GRANULE_BITS;
-       int byte = idx / 8;
-       int bit = idx & 0x7;
-       g_assert (sgen_ptr_in_nursery (pos));
-
-       return (space_bitmap [byte] & (1 << bit)) != 0;
-}
-
-static inline void
-mark_bit (char *pos)
-{
-       int idx = (pos - sgen_nursery_start) >> SPACE_GRANULE_BITS;
-       int byte = idx / 8;
-       int bit = idx & 0x7;
-
-       g_assert (byte < space_bitmap_size);
-       space_bitmap [byte] |= 1 << bit;
-}
-
-static void
-mark_bits_in_range (char *start, char *end)
-{
-       for (;start < end; start += SPACE_GRANULE_IN_BYTES) {
-               mark_bit (start);
-       }
-}
-
-static void
-flip_to_space_bit (void)
-{
-       Fragment **previous, *frag;
-
-       memset (space_bitmap, 0, space_bitmap_size);
-
-       previous = &collector_allocator.alloc_head;
-
-       for (frag = *previous; frag; frag = *previous) {
-               char *start = align_up (frag->fragment_next, SPACE_GRANULE_BITS);
-               char *end = align_down (frag->fragment_end, SPACE_GRANULE_BITS);
-
-               /* Fragment is too small to be usable. */
-               if ((end - start) < SGEN_MAX_NURSERY_WASTE) {
-                       sgen_clear_range (frag->fragment_next, frag->fragment_end);
-                       frag->fragment_next = frag->fragment_end = frag->fragment_start;
-                       *previous = frag->next;
-                       continue;
-               }
-
-               sgen_clear_range (frag->fragment_next, start);
-               sgen_clear_range (end, frag->fragment_end);
-
-               frag->fragment_start = frag->fragment_next = start;
-               frag->fragment_end = end;
-               mark_bits_in_range (start, end);
-               previous = &frag->next;
-       }
-       
-}
-
 void
 sgen_nursery_alloc_prepare_for_minor (void)
 {
-       flip_to_space_bit ();
+       sgen_minor_collector.prepare_to_space (sgen_space_bitmap, sgen_space_bitmap_size);
 }
 
 void
-sgen_nursery_alloc_prepare_for_major (const char *reason)
+sgen_nursery_alloc_prepare_for_major (void)
 {
-       flip_to_space_bit ();
+       sgen_minor_collector.prepare_to_space (sgen_space_bitmap, sgen_space_bitmap_size);
 }
 
 void
 sgen_nursery_allocator_set_nursery_bounds (char *start, char *end)
 {
-       char *middle;
-       /* Setup the single first large fragment */
        sgen_nursery_start = start;
        sgen_nursery_end = end;
 
-       middle = start + (end - start) / 2;
-       add_fragment (&mutator_allocator, start, middle);
-       add_fragment (&collector_allocator, middle, end);
+       sgen_space_bitmap_size = (end - start) / (SGEN_TO_SPACE_GRANULE_IN_BYTES * 8);
+       sgen_space_bitmap = g_malloc0 (sgen_space_bitmap_size);
 
-       promotion_barrier = middle;
-
-       space_bitmap_size = (end - start) / (SPACE_GRANULE_IN_BYTES * 8);
-       space_bitmap = calloc (1, space_bitmap_size);
+       /* Setup the single first large fragment */
+       sgen_minor_collector.init_nursery (&mutator_allocator, start, end);
 }
 
 #endif