Merge pull request #4752 from BrzVlad/feature-dynamic-nrs
authorVlad Brezae <brezaevlad@gmail.com>
Tue, 16 May 2017 00:22:50 +0000 (03:22 +0300)
committerGitHub <noreply@github.com>
Tue, 16 May 2017 00:22:50 +0000 (03:22 +0300)
[sgen] Dynamic nursery sizing

15 files changed:
mono/metadata/sgen-mono.c
mono/sgen/sgen-alloc.c
mono/sgen/sgen-cardtable.c
mono/sgen/sgen-conf.h
mono/sgen/sgen-copy-object.h
mono/sgen/sgen-debug.c
mono/sgen/sgen-gc.c
mono/sgen/sgen-gc.h
mono/sgen/sgen-major-copy-object.h
mono/sgen/sgen-marksweep.c
mono/sgen/sgen-memory-governor.c
mono/sgen/sgen-nursery-allocator.c
mono/sgen/sgen-simple-nursery.c
mono/sgen/sgen-workers.c
mono/tests/Makefile.am

index fc379e52a8f47636618fea8f16a5cc35e64192f2..44adebbc0039700d42ef2ce34d3f9fb5bfd90735 100644 (file)
@@ -2665,7 +2665,7 @@ void*
 mono_gc_get_nursery (int *shift_bits, size_t *size)
 {
        *size = sgen_nursery_size;
-       *shift_bits = DEFAULT_NURSERY_BITS;
+       *shift_bits = sgen_nursery_bits;
        return sgen_get_nursery_start ();
 }
 
index 6f6a45e8b1a9978e8f97ec208bb4b56dde0f519c..2e1178ad3926402057862c87b67dd792684e9026 100644 (file)
@@ -211,7 +211,7 @@ sgen_alloc_obj_nolock (GCVTable vtable, size_t size)
                        /* when running in degraded mode, we continue allocing that way
                         * for a while, to decrease the number of useless nursery collections.
                         */
-                       if (degraded_mode && degraded_mode < DEFAULT_NURSERY_SIZE)
+                       if (degraded_mode && degraded_mode < sgen_nursery_size)
                                return alloc_degraded (vtable, size, FALSE);
 
                        available_in_tlab = (int)(TLAB_REAL_END - TLAB_NEXT);//We'll never have tlabs > 2Gb
index 4fd859ac9fe8e05835b1be0283b4c40b2a3c0d0b..c3a1cf23d3ccf5d5ebdc02361a2a483a7330da95 100644 (file)
@@ -138,7 +138,7 @@ sgen_card_table_wbarrier_range_copy (gpointer _dest, gpointer _src, int size)
        GCObject **dest = (GCObject **)_dest;
        GCObject **src = (GCObject **)_src;
 
-       size_t nursery_bits = DEFAULT_NURSERY_BITS;
+       size_t nursery_bits = sgen_nursery_bits;
        char *start = sgen_nursery_start;
        G_GNUC_UNUSED char *end = sgen_nursery_end;
 
index d9296ca15945b9a4dcfeb066d9751de9c17d9704..63e922c470e0745f5e16340a858be806b08deb2b 100644 (file)
@@ -37,13 +37,6 @@ typedef mword SgenDescriptor;
 #define HEAVY_STAT(x)
 #endif
 
-/*
- * Define this to allow the user to change the nursery size by
- * specifying its value in the MONO_GC_PARAMS environmental
- * variable. See mono_gc_base_init for details.
- */
-#define USER_CONFIG 1
-
 /*
  * The binary protocol enables logging a lot of the GC ativity in a way that is not very
  * intrusive and produces a compact file that can be searched using a custom tool.  This
@@ -211,4 +204,19 @@ typedef mword SgenDescriptor;
 #define SGEN_CEMENT_HASH(hv)   (((hv) ^ ((hv) >> SGEN_CEMENT_HASH_SHIFT)) & (SGEN_CEMENT_HASH_SIZE - 1))
 #define SGEN_CEMENT_THRESHOLD  1000
 
+/*
+ * Default values for the nursery size
+ */
+#define SGEN_DEFAULT_NURSERY_MIN_SIZE  (1 << 19)
+#define SGEN_DEFAULT_NURSERY_SIZE      (1 << 22)
+#define SGEN_DEFAULT_NURSERY_MAX_SIZE  (1 << 25)
+
+/*
+ * We are trying to keep pauses lower than this (ms). We use it for dynamic nursery
+ * sizing heuristics. We are keeping leeway in order to be prepared for work-load
+ * variations.
+ */
+#define SGEN_MAX_PAUSE_TIME 30
+#define SGEN_MAX_PAUSE_MARGIN 0.66f
+
 #endif
index 925af17275dd67a1d2606d0c302b1ba3d7a4c38b..bb97e4a681689a2000318aeed0de938f8d8bfff6 100644 (file)
@@ -108,7 +108,7 @@ copy_object_no_checks_par (GCObject *obj, SgenGrayQueue *queue)
                 */
                gboolean has_references = SGEN_VTABLE_HAS_REFERENCES (vt);
                mword objsize = SGEN_ALIGN_UP (sgen_client_par_object_get_size (vt, obj));
-               destination = major_collector.alloc_object_par (vt, objsize, has_references);
+               destination = COLLECTOR_PARALLEL_ALLOC_FOR_PROMOTION (vt, obj, objsize, has_references);
 
                par_copy_object_no_checks ((char*)destination, vt, obj, objsize);
 
@@ -139,5 +139,6 @@ copy_object_no_checks_par (GCObject *obj, SgenGrayQueue *queue)
 #endif
 
 #undef COLLECTOR_SERIAL_ALLOC_FOR_PROMOTION
+#undef COLLECTOR_PARALLEL_ALLOC_FOR_PROMOTION
 #undef collector_pin_object
 #undef COPY_OR_MARK_PARALLEL
index b519a1ec58eb17750a9407ea4269317c22f57e95..b4da324df1f4bc10ba51959c8fb21f32e4f808ed 100644 (file)
@@ -325,7 +325,7 @@ static void
 setup_valid_nursery_objects (void)
 {
        if (!valid_nursery_objects)
-               valid_nursery_objects = (GCObject **)sgen_alloc_os_memory (DEFAULT_NURSERY_SIZE, (SgenAllocFlags)(SGEN_ALLOC_INTERNAL | SGEN_ALLOC_ACTIVATE), "debugging data", MONO_MEM_ACCOUNT_SGEN_DEBUGGING);
+               valid_nursery_objects = (GCObject **)sgen_alloc_os_memory (sgen_nursery_max_size, (SgenAllocFlags)(SGEN_ALLOC_INTERNAL | SGEN_ALLOC_ACTIVATE), "debugging data", MONO_MEM_ACCOUNT_SGEN_DEBUGGING);
        valid_nursery_object_count = 0;
        sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, setup_mono_sgen_scan_area_with_callback, NULL, FALSE, FALSE);
 }
@@ -1065,10 +1065,10 @@ void
 sgen_dump_section (GCMemSection *section, const char *type)
 {
        char *start = section->data;
-       char *end = section->data + section->size;
+       char *end = section->end_data;
        char *occ_start = NULL;
 
-       fprintf (heap_dump_file, "<section type=\"%s\" size=\"%lu\">\n", type, (unsigned long)section->size);
+       fprintf (heap_dump_file, "<section type=\"%s\" size=\"%lu\">\n", type, (unsigned long)(section->end_data - section->data));
 
        while (start < end) {
                guint size;
@@ -1083,7 +1083,6 @@ sgen_dump_section (GCMemSection *section, const char *type)
                        start += sizeof (void*); /* should be ALLOC_ALIGN, really */
                        continue;
                }
-               g_assert (start < section->next_data);
 
                if (!occ_start)
                        occ_start = start;
index 7f1a8c3d39d912bb35d060f9131d139c41a60d19..66eb9ab194bb76293336041dfca14767efe3fb3a 100644 (file)
@@ -288,6 +288,9 @@ static guint64 time_major_fragment_creation = 0;
 
 static guint64 time_max = 0;
 
+static int sgen_max_pause_time = SGEN_MAX_PAUSE_TIME;
+static float sgen_max_pause_margin = SGEN_MAX_PAUSE_MARGIN;
+
 static SGEN_TV_DECLARE (time_major_conc_collection_start);
 static SGEN_TV_DECLARE (time_major_conc_collection_end);
 
@@ -530,7 +533,7 @@ pin_objects_from_nursery_pin_queue (gboolean do_scan_objects, ScanCopyContext ct
        void **start =  sgen_pinning_get_entry (section->pin_queue_first_entry);
        void **end = sgen_pinning_get_entry (section->pin_queue_last_entry);
        void *start_nursery = section->data;
-       void *end_nursery = section->next_data;
+       void *end_nursery = section->end_data;
        void *last = NULL;
        int count = 0;
        void *search_start;
@@ -946,41 +949,51 @@ sgen_update_heap_boundaries (mword low, mword high)
  * in the nursery. The nursery is stored in nursery_section.
  */
 static void
-alloc_nursery (void)
+alloc_nursery (gboolean dynamic, size_t min_size, size_t max_size)
 {
-       GCMemSection *section;
        char *data;
        size_t scan_starts;
-       size_t alloc_size;
 
-       if (nursery_section)
-               return;
-       SGEN_LOG (2, "Allocating nursery size: %zu", (size_t)sgen_nursery_size);
-       /* later we will alloc a larger area for the nursery but only activate
-        * what we need. The rest will be used as expansion if we have too many pinned
-        * objects in the existing nursery.
-        */
-       /* FIXME: handle OOM */
-       section = (GCMemSection *)sgen_alloc_internal (INTERNAL_MEM_SECTION);
+       if (dynamic) {
+               if (!min_size)
+                       min_size = SGEN_DEFAULT_NURSERY_MIN_SIZE;
+               if (!max_size)
+                       max_size = SGEN_DEFAULT_NURSERY_MAX_SIZE;
+       } else {
+               SGEN_ASSERT (0, min_size == max_size, "We can't have nursery ranges for static configuration.");
+               if (!min_size)
+                       min_size = max_size = SGEN_DEFAULT_NURSERY_SIZE;
+       }
 
-       alloc_size = sgen_nursery_size;
+       SGEN_ASSERT (0, !nursery_section, "Why are we allocating the nursery twice?");
+       SGEN_LOG (2, "Allocating nursery size: %zu, initial %zu", max_size, min_size);
 
-       /* If there isn't enough space even for the nursery we should simply abort. */
-       g_assert (sgen_memgov_try_alloc_space (alloc_size, SPACE_NURSERY));
+       /* FIXME: handle OOM */
+       nursery_section = (GCMemSection *)sgen_alloc_internal (INTERNAL_MEM_SECTION);
 
-       data = (char *)major_collector.alloc_heap (alloc_size, alloc_size, DEFAULT_NURSERY_BITS);
-       sgen_update_heap_boundaries ((mword)data, (mword)(data + sgen_nursery_size));
-       SGEN_LOG (4, "Expanding nursery size (%p-%p): %lu, total: %lu", data, data + alloc_size, (unsigned long)sgen_nursery_size, (unsigned long)sgen_gc_get_total_heap_allocation ());
-       section->data = section->next_data = data;
-       section->size = alloc_size;
-       section->end_data = data + sgen_nursery_size;
-       scan_starts = (alloc_size + SCAN_START_SIZE - 1) / SCAN_START_SIZE;
-       section->scan_starts = (char **)sgen_alloc_internal_dynamic (sizeof (char*) * scan_starts, INTERNAL_MEM_SCAN_STARTS, TRUE);
-       section->num_scan_start = scan_starts;
+       /* If there isn't enough space even for the nursery we should simply abort. */
+       g_assert (sgen_memgov_try_alloc_space (max_size, SPACE_NURSERY));
 
-       nursery_section = section;
+       /*
+        * The nursery section range represents the memory section where objects
+        * can be found. This is used when iterating for objects in the nursery,
+        * pinning etc. sgen_nursery_max_size represents the total allocated space
+        * for the nursery. sgen_nursery_size represents the current size of the
+        * nursery and it is used for allocation limits, heuristics etc. The
+        * nursery section is not always identical to the current nursery size
+        * because it can contain pinned objects from when the nursery was larger.
+        *
+        * sgen_nursery_size <= nursery_section size <= sgen_nursery_max_size
+        */
+       data = (char *)major_collector.alloc_heap (max_size, max_size);
+       sgen_update_heap_boundaries ((mword)data, (mword)(data + max_size));
+       nursery_section->data = data;
+       nursery_section->end_data = data + min_size;
+       scan_starts = (max_size + SCAN_START_SIZE - 1) / SCAN_START_SIZE;
+       nursery_section->scan_starts = (char **)sgen_alloc_internal_dynamic (sizeof (char*) * scan_starts, INTERNAL_MEM_SCAN_STARTS, TRUE);
+       nursery_section->num_scan_start = scan_starts;
 
-       sgen_nursery_allocator_set_nursery_bounds (data, data + sgen_nursery_size);
+       sgen_nursery_allocator_set_nursery_bounds (data, min_size, max_size);
 }
 
 FILE *
@@ -1333,6 +1346,16 @@ scan_copy_context_for_scan_job (void *worker_data_untyped, ScanJob *job)
 {
        WorkerData *worker_data = (WorkerData *)worker_data_untyped;
 
+       if (!job->ops) {
+               /*
+                * For jobs enqueued on workers we set the ops at job runtime in order
+                * to be able to profit from on the fly optimized object ops or other
+                * object ops changes, like forced concurrent finish.
+                */
+               SGEN_ASSERT (0, sgen_workers_is_worker_thread (mono_native_thread_id_get ()), "We need a context for the scan job");
+               job->ops = sgen_workers_get_idle_func_object_ops ();
+       }
+
        return CONTEXT_FROM_OBJECT_OPERATIONS (job->ops, sgen_workers_get_job_gray_queue (worker_data, job->gc_thread_gray_queue));
 }
 
@@ -1481,7 +1504,6 @@ workers_finish_callback (void)
        /* Mod union preclean jobs */
        for (i = 0; i < split_count; i++) {
                psj = (ParallelScanJob*)sgen_thread_pool_job_alloc ("preclean major mod union cardtable", job_major_mod_union_preclean, sizeof (ParallelScanJob));
-               psj->scan_job.ops = sgen_workers_get_idle_func_object_ops ();
                psj->scan_job.gc_thread_gray_queue = NULL;
                psj->job_index = i;
                sgen_workers_enqueue_job (&psj->scan_job.job, TRUE);
@@ -1489,14 +1511,12 @@ workers_finish_callback (void)
 
        for (i = 0; i < split_count; i++) {
                psj = (ParallelScanJob*)sgen_thread_pool_job_alloc ("preclean los mod union cardtable", job_los_mod_union_preclean, sizeof (ParallelScanJob));
-               psj->scan_job.ops = sgen_workers_get_idle_func_object_ops ();
                psj->scan_job.gc_thread_gray_queue = NULL;
                psj->job_index = i;
                sgen_workers_enqueue_job (&psj->scan_job.job, TRUE);
        }
 
        sj = (ScanJob*)sgen_thread_pool_job_alloc ("scan last pinned", job_scan_last_pinned, sizeof (ScanJob));
-       sj->ops = sgen_workers_get_idle_func_object_ops ();
        sj->gc_thread_gray_queue = NULL;
        sgen_workers_enqueue_job (&sj->job, TRUE);
 }
@@ -1598,12 +1618,11 @@ static gboolean
 collect_nursery (const char *reason, gboolean is_overflow, SgenGrayQueue *unpin_queue)
 {
        gboolean needs_major, is_parallel = FALSE;
-       size_t max_garbage_amount;
-       char *nursery_next;
        mword fragment_total;
        SgenGrayQueue gc_thread_gray_queue;
        SgenObjectOperations *object_ops_nopar, *object_ops_par = NULL;
        ScanCopyContext ctx;
+       int duration;
        TV_DECLARE (atv);
        TV_DECLARE (btv);
        SGEN_TV_DECLARE (last_minor_collection_start_tv);
@@ -1643,13 +1662,8 @@ collect_nursery (const char *reason, gboolean is_overflow, SgenGrayQueue *unpin_
 
        degraded_mode = 0;
        objects_pinned = 0;
-       nursery_next = sgen_nursery_alloc_get_upper_alloc_bound ();
-       /* FIXME: optimize later to use the higher address where an object can be present */
-       nursery_next = MAX (nursery_next, sgen_get_nursery_end ());
 
-       SGEN_LOG (1, "Start nursery collection %d %p-%p, size: %d", gc_stats.minor_gc_count, sgen_get_nursery_start (), nursery_next, (int)(nursery_next - sgen_get_nursery_start ()));
-       max_garbage_amount = nursery_next - sgen_get_nursery_start ();
-       g_assert (nursery_section->size >= max_garbage_amount);
+       SGEN_LOG (1, "Start nursery collection %d %p-%p, size: %d", gc_stats.minor_gc_count, nursery_section->data, nursery_section->end_data, (int)(nursery_section->end_data - nursery_section->data));
 
        /* world must be stopped already */
        TV_GETTIME (btv);
@@ -1657,8 +1671,6 @@ collect_nursery (const char *reason, gboolean is_overflow, SgenGrayQueue *unpin_
 
        sgen_client_pre_collection_checks ();
 
-       nursery_section->next_data = nursery_next;
-
        major_collector.start_nursery_collection ();
 
        sgen_memgov_minor_collection_start ();
@@ -1673,7 +1685,7 @@ collect_nursery (const char *reason, gboolean is_overflow, SgenGrayQueue *unpin_
        /* pin from pinned handles */
        sgen_init_pinning ();
        sgen_client_binary_protocol_mark_start (GENERATION_NURSERY);
-       pin_from_roots (sgen_get_nursery_start (), nursery_next, ctx);
+       pin_from_roots (nursery_section->data, nursery_section->end_data, ctx);
        /* pin cemented objects */
        sgen_pin_cemented_objects ();
        /* identify pinned objects */
@@ -1698,7 +1710,7 @@ collect_nursery (const char *reason, gboolean is_overflow, SgenGrayQueue *unpin_
 
        remset.start_scan_remsets ();
 
-       enqueue_scan_remembered_set_jobs (&gc_thread_gray_queue, is_parallel ? object_ops_par : object_ops_nopar, is_parallel);
+       enqueue_scan_remembered_set_jobs (&gc_thread_gray_queue, is_parallel ? NULL : object_ops_nopar, is_parallel);
 
        /* we don't have complete write barrier yet, so we scan all the old generation sections */
        TV_GETTIME (btv);
@@ -1713,7 +1725,7 @@ collect_nursery (const char *reason, gboolean is_overflow, SgenGrayQueue *unpin_
        TV_GETTIME (atv);
        time_minor_scan_pinned += TV_ELAPSED (btv, atv);
 
-       enqueue_scan_from_roots_jobs (&gc_thread_gray_queue, sgen_get_nursery_start (), nursery_next, is_parallel ? object_ops_par : object_ops_nopar, is_parallel);
+       enqueue_scan_from_roots_jobs (&gc_thread_gray_queue, nursery_section->data, nursery_section->end_data, is_parallel ? NULL : object_ops_nopar, is_parallel);
 
        if (is_parallel) {
                gray_queue_redirect (&gc_thread_gray_queue);
@@ -1742,6 +1754,14 @@ collect_nursery (const char *reason, gboolean is_overflow, SgenGrayQueue *unpin_
        if (remset_consistency_checks)
                sgen_check_remset_consistency ();
 
+
+       TV_GETTIME (btv);
+       duration = (int)(TV_ELAPSED (last_minor_collection_start_tv, btv) / 10000);
+       if (duration > (sgen_max_pause_time * sgen_max_pause_margin))
+               sgen_resize_nursery (TRUE);
+       else
+               sgen_resize_nursery (FALSE);
+
        /* 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.
@@ -1844,12 +1864,6 @@ major_copy_or_mark_from_roots (SgenGrayQueue *gc_thread_gray_queue, size_t *old_
        TV_GETTIME (btv);
        time_major_pre_collection_fragment_clear += TV_ELAPSED (atv, btv);
 
-       if (!sgen_collection_is_concurrent ())
-               nursery_section->next_data = sgen_get_nursery_end ();
-       /* we should also coalesce scanning from sections close to each other
-        * and deal with pointers outside of the sections later.
-        */
-
        objects_pinned = 0;
 
        sgen_client_pre_collection_checks ();
@@ -1994,13 +2008,13 @@ major_copy_or_mark_from_roots (SgenGrayQueue *gc_thread_gray_queue, size_t *old_
                        ParallelScanJob *psj;
 
                        psj = (ParallelScanJob*)sgen_thread_pool_job_alloc ("scan mod union cardtable", job_scan_major_mod_union_card_table, sizeof (ParallelScanJob));
-                       psj->scan_job.ops = object_ops_par ? object_ops_par : object_ops_nopar;
+                       psj->scan_job.ops = parallel ? NULL : object_ops_nopar;
                        psj->scan_job.gc_thread_gray_queue = gc_thread_gray_queue;
                        psj->job_index = i;
                        sgen_workers_enqueue_job (&psj->scan_job.job, parallel);
 
                        psj = (ParallelScanJob*)sgen_thread_pool_job_alloc ("scan LOS mod union cardtable", job_scan_los_mod_union_card_table, sizeof (ParallelScanJob));
-                       psj->scan_job.ops = object_ops_par ? object_ops_par : object_ops_nopar;
+                       psj->scan_job.ops = parallel ? NULL : object_ops_nopar;
                        psj->scan_job.gc_thread_gray_queue = gc_thread_gray_queue;
                        psj->job_index = i;
                        sgen_workers_enqueue_job (&psj->scan_job.job, parallel);
@@ -2945,7 +2959,7 @@ sgen_gc_get_used_size (void)
        gint64 tot = 0;
        LOCK_GC;
        tot = los_memory_usage;
-       tot += nursery_section->next_data - nursery_section->data;
+       tot += nursery_section->end_data - nursery_section->data;
        tot += major_collector.get_used_size ();
        /* FIXME: account for pinned objects */
        UNLOCK_GC;
@@ -3000,6 +3014,8 @@ sgen_gc_init (void)
        gboolean debug_print_allowance = FALSE;
        double allowance_ratio = 0, save_target = 0;
        gboolean cement_enabled = TRUE;
+       gboolean dynamic_nursery = FALSE;
+       size_t min_nursery_size = 0, max_nursery_size = 0;
 
        do {
                result = InterlockedCompareExchange (&gc_initialized, -1, 0);
@@ -3097,8 +3113,6 @@ sgen_gc_init (void)
                goto use_default_major;
        }
 
-       sgen_nursery_size = DEFAULT_NURSERY_SIZE;
-
        if (opts) {
                gboolean usage_printed = FALSE;
 
@@ -3135,8 +3149,6 @@ sgen_gc_init (void)
                                }
                                continue;
                        }
-
-#ifdef USER_CONFIG
                        if (g_str_has_prefix (opt, "nursery-size=")) {
                                size_t val;
                                opt = strchr (opt, '=') + 1;
@@ -3152,17 +3164,14 @@ sgen_gc_init (void)
                                                continue;
                                        }
 
-                                       sgen_nursery_size = val;
-                                       sgen_nursery_bits = 0;
-                                       while (ONE_P << (++ sgen_nursery_bits) != sgen_nursery_size)
-                                               ;
+                                       min_nursery_size = max_nursery_size = val;
+                                       dynamic_nursery = FALSE;
                                } else {
                                        sgen_env_var_error (MONO_GC_PARAMS_NAME, "Using default value.", "`nursery-size` must be an integer.");
                                        continue;
                                }
                                continue;
                        }
-#endif
                        if (g_str_has_prefix (opt, "save-target-ratio=")) {
                                double val;
                                opt = strchr (opt, '=') + 1;
@@ -3200,6 +3209,19 @@ sgen_gc_init (void)
                                continue;
                        }
 
+                       if (!strcmp (opt, "dynamic-nursery")) {
+                               if (sgen_minor_collector.is_split)
+                                       sgen_env_var_error (MONO_GC_PARAMS_NAME, "Using default value.",
+                                                       "dynamic-nursery not supported with split-nursery.");
+                               else
+                                       dynamic_nursery = TRUE;
+                               continue;
+                       }
+                       if (!strcmp (opt, "no-dynamic-nursery")) {
+                               dynamic_nursery = FALSE;
+                               continue;
+                       }
+
                        if (major_collector.handle_gc_param && major_collector.handle_gc_param (opt))
                                continue;
 
@@ -3222,6 +3244,7 @@ sgen_gc_init (void)
                        fprintf (stderr, "  minor=COLLECTOR (where COLLECTOR is `simple' or `split')\n");
                        fprintf (stderr, "  wbarrier=WBARRIER (where WBARRIER is `remset' or `cardtable')\n");
                        fprintf (stderr, "  [no-]cementing\n");
+                       fprintf (stderr, "  [no-]dynamic-nursery\n");
                        if (major_collector.print_gc_param_usage)
                                major_collector.print_gc_param_usage ();
                        if (sgen_minor_collector.print_gc_param_usage)
@@ -3246,7 +3269,7 @@ sgen_gc_init (void)
        if (params_opts)
                g_free (params_opts);
 
-       alloc_nursery ();
+       alloc_nursery (dynamic_nursery, min_nursery_size, max_nursery_size);
 
        sgen_pinning_init ();
        sgen_cement_init (cement_enabled);
index db2e35a292fb19d7ddf161eac6c4058747fe9993..e3fe2ed226789a0ae463ea897242c9614ad89e6f 100644 (file)
@@ -60,9 +60,6 @@ NurseryClearPolicy sgen_get_nursery_clear_policy (void);
 typedef struct _GCMemSection GCMemSection;
 struct _GCMemSection {
        char *data;
-       mword size;
-       /* pointer where more data could be allocated if it fits */
-       char *next_data;
        char *end_data;
        /*
         * scan starts is an array of pointers to objects equally spaced in the allocation area
@@ -186,29 +183,17 @@ sgen_aligned_addr_hash (gconstpointer ptr)
 
 #define SGEN_PTR_IN_NURSERY(p,bits,start,end)  (((mword)(p) & ~(((mword)1 << (bits)) - 1)) == (mword)(start))
 
-#ifdef USER_CONFIG
-
-/* good sizes are 512KB-1MB: larger ones increase a lot memzeroing time */
-#define DEFAULT_NURSERY_SIZE (sgen_nursery_size)
 extern size_t sgen_nursery_size;
-/* The number of trailing 0 bits in DEFAULT_NURSERY_SIZE */
-#define DEFAULT_NURSERY_BITS (sgen_nursery_bits)
+extern size_t sgen_nursery_max_size;
 extern int sgen_nursery_bits;
 
-#else
-
-#define DEFAULT_NURSERY_SIZE (4*1024*1024)
-#define DEFAULT_NURSERY_BITS 22
-
-#endif
-
 extern char *sgen_nursery_start;
 extern char *sgen_nursery_end;
 
 static inline MONO_ALWAYS_INLINE gboolean
 sgen_ptr_in_nursery (void *p)
 {
-       return SGEN_PTR_IN_NURSERY ((p), DEFAULT_NURSERY_BITS, sgen_nursery_start, sgen_nursery_end);
+       return SGEN_PTR_IN_NURSERY ((p), sgen_nursery_bits, sgen_nursery_start, sgen_nursery_end);
 }
 
 static inline MONO_ALWAYS_INLINE char*
@@ -495,7 +480,6 @@ typedef struct {
 
 void sgen_fragment_allocator_add (SgenFragmentAllocator *allocator, char *start, char *end);
 void sgen_fragment_allocator_release (SgenFragmentAllocator *allocator);
-void* sgen_fragment_allocator_serial_alloc (SgenFragmentAllocator *allocator, size_t size);
 void* sgen_fragment_allocator_par_alloc (SgenFragmentAllocator *allocator, size_t size);
 void* sgen_fragment_allocator_serial_range_alloc (SgenFragmentAllocator *allocator, size_t desired_size, size_t minimum_size, size_t *out_alloc_size);
 void* sgen_fragment_allocator_par_range_alloc (SgenFragmentAllocator *allocator, size_t desired_size, size_t minimum_size, size_t *out_alloc_size);
@@ -563,6 +547,7 @@ typedef struct {
        gboolean is_parallel;
 
        GCObject* (*alloc_for_promotion) (GCVTable vtable, GCObject *obj, size_t objsize, gboolean has_references);
+       GCObject* (*alloc_for_promotion_par) (GCVTable vtable, GCObject *obj, size_t objsize, gboolean has_references);
 
        SgenObjectOperations serial_ops;
        SgenObjectOperations serial_ops_with_concurrent_major;
@@ -640,7 +625,7 @@ struct _SgenMajorCollector {
        gboolean supports_cardtable;
        gboolean sweeps_lazily;
 
-       void* (*alloc_heap) (mword nursery_size, mword nursery_align, int nursery_bits);
+       void* (*alloc_heap) (mword nursery_size, mword nursery_align);
        gboolean (*is_object_live) (GCObject *obj);
        GCObject* (*alloc_small_pinned_obj) (GCVTable vtable, size_t size, gboolean has_references);
        GCObject* (*alloc_degraded) (GCVTable vtable, size_t size);
@@ -912,12 +897,12 @@ void sgen_los_mark_mod_union_card (GCObject *mono_obj, void **ptr);
 
 void sgen_clear_nursery_fragments (void);
 void sgen_nursery_allocator_prepare_for_pinning (void);
-void sgen_nursery_allocator_set_nursery_bounds (char *nursery_start, char *nursery_end);
+void sgen_nursery_allocator_set_nursery_bounds (char *nursery_start, size_t min_size, size_t max_size);
+void sgen_resize_nursery (gboolean need_shrink);
 mword sgen_build_nursery_fragments (GCMemSection *nursery_section, SgenGrayQueue *unpin_queue);
 void sgen_init_nursery_allocator (void);
 void sgen_nursery_allocator_init_heavy_stats (void);
 void sgen_init_allocator (void);
-char* sgen_nursery_alloc_get_upper_alloc_bound (void);
 void* sgen_nursery_alloc (size_t size);
 void* sgen_nursery_alloc_range (size_t size, size_t min_size, size_t *out_alloc_size);
 gboolean sgen_can_alloc_size (size_t size);
index e04bf9e063cf1727207af8ae62bbb5892d563936..b110a75d847a65adba6d90a3443a6b1648a1c985 100644 (file)
@@ -19,5 +19,6 @@
 } while (0)
 
 #define COLLECTOR_SERIAL_ALLOC_FOR_PROMOTION sgen_minor_collector.alloc_for_promotion
+#define COLLECTOR_PARALLEL_ALLOC_FOR_PROMOTION sgen_minor_collector.alloc_for_promotion_par
 
 #include "sgen-copy-object.h"
index 04ab32dab84a0dbc96e64bf00e7293ed6eee2e8d..12b06055affe554380a649ef0085072f8e4a85c5 100644 (file)
@@ -306,7 +306,7 @@ ms_find_block_obj_size_index (size_t size)
         ms_find_block_obj_size_index ((s)))
 
 static void*
-major_alloc_heap (mword nursery_size, mword nursery_align, int the_nursery_bits)
+major_alloc_heap (mword nursery_size, mword nursery_align)
 {
        char *start;
        if (nursery_align)
index 3bf90115b854910c743596a6e32c1a061e35d734..17fed16754ba8ba61a0e67f5c88f5c8c79870cc0 100644 (file)
@@ -23,7 +23,7 @@
 #include "mono/sgen/sgen-workers.h"
 #include "mono/sgen/sgen-client.h"
 
-#define MIN_MINOR_COLLECTION_ALLOWANCE ((mword)(DEFAULT_NURSERY_SIZE * default_allowance_nursery_size_ratio))
+#define MIN_MINOR_COLLECTION_ALLOWANCE ((mword)(SGEN_DEFAULT_NURSERY_SIZE * default_allowance_nursery_size_ratio))
 
 static SgenPointerQueue log_entries = SGEN_POINTER_QUEUE_INIT (INTERNAL_MEM_TEMPORARY);
 static MonoCoopMutex log_entries_mutex;
@@ -492,11 +492,11 @@ sgen_memgov_init (size_t max_heap, size_t soft_limit, gboolean debug_allowance,
                max_heap = soft_limit;
        }
 
-       if (max_heap < sgen_nursery_size * 4) {
+       if (max_heap < SGEN_DEFAULT_NURSERY_SIZE * 4) {
                sgen_env_var_error (MONO_GC_PARAMS_NAME, "Setting to minimum.", "`max-heap-size` must be at least 4 times as large as `nursery size`.");
-               max_heap = sgen_nursery_size * 4;
+               max_heap = SGEN_DEFAULT_NURSERY_SIZE * 4;
        }
-       max_heap_size = max_heap - sgen_nursery_size;
+       max_heap_size = max_heap - SGEN_DEFAULT_NURSERY_SIZE;
 
        if (allowance_ratio)
                default_allowance_nursery_size_ratio = allowance_ratio;
index 91611877ce6423b43acd2a6c690ac36c884bc5db..53a7999a74e88ff75f06565f4c59fb3134f510b6 100644 (file)
@@ -66,16 +66,21 @@ static SgenFragmentAllocator mutator_allocator;
 /* freeelist of fragment structures */
 static SgenFragment *fragment_freelist = NULL;
 
-/* Allocator cursors */
-static char *nursery_last_pinned_end = NULL;
-
 char *sgen_nursery_start;
 char *sgen_nursery_end;
 
-#ifdef USER_CONFIG
-size_t sgen_nursery_size = (1 << 22);
-int sgen_nursery_bits = 22;
-#endif
+/* good sizes are 512KB-1MB: larger ones increase a lot memzeroing time */
+size_t sgen_nursery_size;
+/*
+ * Maximum size that we can resize the nursery to.
+ * If sgen_nursery_default_size == sgen_nursery_max_size then we are not
+ * dynamically resizing the nursery
+ */
+size_t sgen_nursery_max_size;
+size_t sgen_nursery_min_size;
+/* The number of trailing 0 bits in sgen_nursery_max_size */
+int sgen_nursery_bits;
+
 
 char *sgen_space_bitmap;
 size_t sgen_space_bitmap_size;
@@ -345,7 +350,7 @@ par_alloc_from_fragment (SgenFragmentAllocator *allocator, SgenFragment *frag, s
        char *p = frag->fragment_next;
        char *end = p + size;
 
-       if (end > frag->fragment_end)
+       if (end > frag->fragment_end || end > (sgen_nursery_start + sgen_nursery_size))
                return NULL;
 
        /* p = frag->fragment_next must happen before */
@@ -439,9 +444,14 @@ sgen_fragment_allocator_par_alloc (SgenFragmentAllocator *allocator, size_t size
 
 restart:
        for (frag = (SgenFragment *)unmask (allocator->alloc_head); unmask (frag); frag = (SgenFragment *)unmask (frag->next)) {
+               size_t frag_size = frag->fragment_end - frag->fragment_next;
+
+               if (frag->fragment_next >= (sgen_nursery_start + sgen_nursery_size))
+                       continue;
+
                HEAVY_STAT (++stat_alloc_iterations);
 
-               if (size <= (size_t)(frag->fragment_end - frag->fragment_next)) {
+               if (size <= frag_size) {
                        void *p = par_alloc_from_fragment (allocator, frag, size);
                        if (!p) {
                                HEAVY_STAT (++stat_alloc_retries);
@@ -456,33 +466,6 @@ restart:
        return NULL;
 }
 
-void*
-sgen_fragment_allocator_serial_alloc (SgenFragmentAllocator *allocator, size_t size)
-{
-       SgenFragment *frag;
-       SgenFragment **previous;
-#ifdef NALLOC_DEBUG
-       InterlockedIncrement (&alloc_count);
-#endif
-
-       previous = &allocator->alloc_head;
-
-       for (frag = *previous; frag; frag = *previous) {
-               char *p = (char *)serial_alloc_from_fragment (previous, frag, size);
-
-               HEAVY_STAT (++stat_alloc_iterations);
-
-               if (p) {
-#ifdef NALLOC_DEBUG
-                       add_alloc_record (p, size, FIXED_ALLOC);
-#endif
-                       return p;
-               }
-               previous = &frag->next;
-       }
-       return NULL;
-}
-
 void*
 sgen_fragment_allocator_serial_range_alloc (SgenFragmentAllocator *allocator, size_t desired_size, size_t minimum_size, size_t *out_alloc_size)
 {
@@ -551,6 +534,9 @@ restart:
        for (frag = (SgenFragment *)unmask (allocator->alloc_head); frag; frag = (SgenFragment *)unmask (frag->next)) {
                size_t frag_size = frag->fragment_end - frag->fragment_next;
 
+               if (frag->fragment_next >= (sgen_nursery_start + sgen_nursery_size))
+                       continue;
+
                HEAVY_STAT (++stat_alloc_range_iterations);
 
                if (desired_size <= frag_size) {
@@ -578,9 +564,8 @@ restart:
 
        if (min_frag) {
                void *p;
-               size_t frag_size;
+               size_t frag_size = min_frag->fragment_end - min_frag->fragment_next;
 
-               frag_size = min_frag->fragment_end - min_frag->fragment_next;
                if (frag_size < minimum_size)
                        goto restart;
 
@@ -705,6 +690,26 @@ fragment_list_reverse (SgenFragmentAllocator *allocator)
        allocator->region_head = allocator->alloc_head = prev;
 }
 
+/*
+ * We split fragments at the border of the current nursery limit. When we
+ * allocate from the nursery we only consider fragments that start in the
+ * current nursery section. We build fragments for the entire nursery in
+ * order to facilitate scanning it for objects (adding a nursery frag also
+ * marks a region in the nursery as being free)
+ */
+static void
+add_nursery_frag_checks (SgenFragmentAllocator *allocator, char *frag_start, char *frag_end)
+{
+       char *nursery_limit = sgen_nursery_start + sgen_nursery_size;
+
+       if (frag_start < nursery_limit && frag_end > nursery_limit) {
+               add_nursery_frag (allocator, nursery_limit - frag_start, frag_start, nursery_limit);
+               add_nursery_frag (allocator, frag_end - nursery_limit, nursery_limit, frag_end);
+       } else {
+               add_nursery_frag (allocator, frag_end - frag_start, frag_start, frag_end);
+       }
+}
+
 mword
 sgen_build_nursery_fragments (GCMemSection *nursery_section, SgenGrayQueue *unpin_queue)
 {
@@ -765,7 +770,7 @@ sgen_build_nursery_fragments (GCMemSection *nursery_section, SgenGrayQueue *unpi
                g_assert (frag_size >= 0);
                g_assert (size > 0);
                if (frag_size && size)
-                       add_nursery_frag (&mutator_allocator, frag_size, frag_start, frag_end); 
+                       add_nursery_frag_checks (&mutator_allocator, frag_start, frag_end);
 
                frag_size = size;
 #ifdef NALLOC_DEBUG
@@ -774,11 +779,10 @@ sgen_build_nursery_fragments (GCMemSection *nursery_section, SgenGrayQueue *unpi
                frag_start = frag_end + frag_size;
        }
 
-       nursery_last_pinned_end = frag_start;
        frag_end = sgen_nursery_end;
        frag_size = frag_end - frag_start;
        if (frag_size)
-               add_nursery_frag (&mutator_allocator, frag_size, frag_start, frag_end);
+               add_nursery_frag_checks (&mutator_allocator, frag_start, frag_end);
 
        /* Now it's safe to release the fragments exclude list. */
        sgen_minor_collector.build_fragments_release_exclude_head ();
@@ -799,13 +803,6 @@ sgen_build_nursery_fragments (GCMemSection *nursery_section, SgenGrayQueue *unpi
        return fragment_total;
 }
 
-char *
-sgen_nursery_alloc_get_upper_alloc_bound (void)
-{
-       /*FIXME we need to calculate the collector upper bound as well, but this must be done in the previous GC. */
-       return sgen_nursery_end;
-}
-
 /*** Nursery memory allocation ***/
 void
 sgen_nursery_retire_region (void *address, ptrdiff_t size)
@@ -897,21 +894,59 @@ sgen_nursery_alloc_prepare_for_major (void)
 }
 
 void
-sgen_nursery_allocator_set_nursery_bounds (char *start, char *end)
+sgen_nursery_allocator_set_nursery_bounds (char *start, size_t min_size, size_t max_size)
 {
        sgen_nursery_start = start;
-       sgen_nursery_end = end;
+       sgen_nursery_end = start + max_size;
+
+       sgen_nursery_size = min_size;
+       sgen_nursery_min_size = min_size;
+       sgen_nursery_max_size = max_size;
+
+       sgen_nursery_bits = 0;
+       while (ONE_P << (++ sgen_nursery_bits) != sgen_nursery_max_size)
+               ;
 
        /*
         * This will not divide evenly for tiny nurseries (<4kb), so we make sure to be on
         * the right side of things and round up.  We could just do a MIN(1,x) instead,
         * since the nursery size must be a power of 2.
         */
-       sgen_space_bitmap_size = (end - start + SGEN_TO_SPACE_GRANULE_IN_BYTES * 8 - 1) / (SGEN_TO_SPACE_GRANULE_IN_BYTES * 8);
+       sgen_space_bitmap_size = (sgen_nursery_end - sgen_nursery_start + SGEN_TO_SPACE_GRANULE_IN_BYTES * 8 - 1) / (SGEN_TO_SPACE_GRANULE_IN_BYTES * 8);
        sgen_space_bitmap = (char *)g_malloc0 (sgen_space_bitmap_size);
 
        /* Setup the single first large fragment */
-       sgen_minor_collector.init_nursery (&mutator_allocator, start, end);
+       sgen_minor_collector.init_nursery (&mutator_allocator, sgen_nursery_start, sgen_nursery_end);
 }
 
+void
+sgen_resize_nursery (gboolean need_shrink)
+{
+       size_t major_size;
+
+       if (sgen_nursery_min_size == sgen_nursery_max_size)
+               return;
+
+       major_size = major_collector.get_num_major_sections () * major_collector.section_size + los_memory_usage;
+       /*
+        * We attempt to use a larger nursery size, as long as it doesn't
+        * exceed a certain percentage of the major heap.
+        *
+        * FIXME
+        * Commit memory when expanding and release it when shrinking (which
+        * would only be possible if there aren't any pinned objects in the
+        * section).
+        */
+       if ((sgen_nursery_size * 2) < (major_size / SGEN_DEFAULT_ALLOWANCE_NURSERY_SIZE_RATIO) &&
+                       (sgen_nursery_size * 2) <= sgen_nursery_max_size && !need_shrink) {
+               if ((nursery_section->end_data - nursery_section->data) == sgen_nursery_size)
+                       nursery_section->end_data += sgen_nursery_size;
+               sgen_nursery_size *= 2;
+       } else if ((sgen_nursery_size > (major_size / SGEN_DEFAULT_ALLOWANCE_NURSERY_SIZE_RATIO) || need_shrink) &&
+                       (sgen_nursery_size / 2) >= sgen_nursery_min_size) {
+               sgen_nursery_size /= 2;
+       }
+}
+
+
 #endif
index 4234559e9e8cec8ced5617f60fe64e9e9e862c38..39d08abcf16027b60b884376a02acbc9a2517ea3 100644 (file)
@@ -28,6 +28,19 @@ alloc_for_promotion (GCVTable vtable, GCObject *obj, size_t objsize, gboolean ha
        return major_collector.alloc_object (vtable, objsize, has_references);
 }
 
+static inline GCObject*
+alloc_for_promotion_par (GCVTable vtable, GCObject *obj, size_t objsize, gboolean has_references)
+{
+       /*
+        * FIXME
+        * Note that the stat is not precise. total_promoted_size incrementing is not atomic and
+        * even in that case, the same object might be promoted simultaneously by different workers
+        * leading to one of the allocated major object to be discarded.
+        */
+       total_promoted_size += objsize;
+       return major_collector.alloc_object_par (vtable, objsize, has_references);
+}
+
 static SgenFragment*
 build_fragments_get_exclude_head (void)
 {
@@ -57,7 +70,14 @@ clear_fragments (void)
 static void
 init_nursery (SgenFragmentAllocator *allocator, char *start, char *end)
 {
-       sgen_fragment_allocator_add (allocator, start, end);
+       char *nursery_limit = sgen_nursery_start + sgen_nursery_size;
+
+       if (start < nursery_limit && end > nursery_limit) {
+               sgen_fragment_allocator_add (allocator, start, nursery_limit);
+               sgen_fragment_allocator_add (allocator, nursery_limit, end);
+       } else {
+               sgen_fragment_allocator_add (allocator, start, end);
+       }
 }
 
 
@@ -65,6 +85,7 @@ init_nursery (SgenFragmentAllocator *allocator, char *start, char *end)
 
 #define collector_pin_object(obj, queue) sgen_pin_object (obj, queue);
 #define COLLECTOR_SERIAL_ALLOC_FOR_PROMOTION alloc_for_promotion
+#define COLLECTOR_PARALLEL_ALLOC_FOR_PROMOTION alloc_for_promotion_par
 
 #define COPY_OR_MARK_PARALLEL
 #include "sgen-copy-object.h"
@@ -113,6 +134,7 @@ sgen_simple_nursery_init (SgenMinorCollector *collector, gboolean parallel)
        collector->is_parallel = parallel;
 
        collector->alloc_for_promotion = alloc_for_promotion;
+       collector->alloc_for_promotion_par = alloc_for_promotion_par;
 
        collector->prepare_to_space = prepare_to_space;
        collector->clear_fragments = clear_fragments;
index 47fb00d9e1f8db39461cc62ff7a29c126ffedf61..82d637d2b2674c12cca0fb0331d4966fe8085a6f 100644 (file)
@@ -22,6 +22,7 @@
 
 static int workers_num;
 static int active_workers_num;
+static volatile gboolean started;
 static volatile gboolean forced_stop;
 static WorkerData *workers_data;
 static SgenWorkerCallback worker_init_cb;
@@ -313,7 +314,7 @@ should_work_func (void *data_untyped)
        WorkerData *data = (WorkerData*)data_untyped;
        int current_worker = (int) (data - workers_data);
 
-       return current_worker < active_workers_num;
+       return started && current_worker < active_workers_num;
 }
 
 static void
@@ -415,6 +416,8 @@ sgen_workers_stop_all_workers (void)
        sgen_thread_pool_wait_for_all_jobs (pool);
        sgen_thread_pool_idle_wait (pool);
        SGEN_ASSERT (0, sgen_workers_all_done (), "Can only signal enqueue work when in no work state");
+
+       started = FALSE;
 }
 
 void
@@ -431,11 +434,14 @@ sgen_workers_set_num_active_workers (int num_workers)
 void
 sgen_workers_start_all_workers (SgenObjectOperations *object_ops_nopar, SgenObjectOperations *object_ops_par, SgenWorkersFinishCallback callback)
 {
+       SGEN_ASSERT (0, !started, "Why are we starting to work without finishing previous cycle");
+
        idle_func_object_ops_par = object_ops_par;
        idle_func_object_ops_nopar = object_ops_nopar;
        forced_stop = FALSE;
        finish_callback = callback;
        worker_awakenings = 0;
+       started = TRUE;
        mono_memory_write_barrier ();
 
        /*
@@ -461,6 +467,8 @@ sgen_workers_join (void)
        SGEN_ASSERT (0, sgen_section_gray_queue_is_empty (&workers_distribute_gray_queue), "Why is there still work left to do?");
        for (i = 0; i < active_workers_num; ++i)
                SGEN_ASSERT (0, sgen_gray_object_queue_is_empty (&workers_data [i].private_gray_queue), "Why is there still work left to do?");
+
+       started = FALSE;
 }
 
 /*
@@ -528,7 +536,8 @@ sgen_workers_take_from_queue (SgenGrayQueue *queue)
 SgenObjectOperations*
 sgen_workers_get_idle_func_object_ops (void)
 {
-       return (idle_func_object_ops_par) ? idle_func_object_ops_par : idle_func_object_ops_nopar;
+       g_assert (idle_func_object_ops);
+       return idle_func_object_ops;
 }
 
 /*
index 2ef7f4e313cf7385579e5048e983a25d9e27a395..ac930c45ade6c9021596cfe57de804988721c3f0 100644 (file)
@@ -1436,10 +1436,10 @@ test-stress-sgen-regular: $(TESTS_SGEN_REGULAR) $(TESTSAOT_SGEN_REGULAR)
        $(MAKE) test-sgen-regular-ms-conc-par-simple MONO_TESTS_STRESS=1 || ok=false; \
        $(MAKE) test-sgen-regular-ms-conc-split MONO_TESTS_STRESS=1 || ok=false; \
        $(MAKE) test-sgen-regular-ms-conc-split-95-clear-at-gc MONO_TESTS_STRESS=1 || ok=false; \
-       $(MAKE) test-sgen-regular-ms-conc-par-simple-par MONO_TESTS_STRESS=1 || ok=false; \
+       $(MAKE) test-sgen-regular-ms-conc-par-simple-par-dyn MONO_TESTS_STRESS=1 || ok=false; \
        $(MAKE) test-sgen-regular-ms-conc-par-simple-par-512k MONO_TESTS_STRESS=1 || ok=false; \
        $(MAKE) test-sgen-regular-ms-conc-par-simple-par-32m MONO_TESTS_STRESS=1 || ok=false; \
-       $(MAKE) test-sgen-regular-ms-conc-par-simple-par-clear-at-gc MONO_TESTS_STRESS=1 || ok=false; \
+       $(MAKE) test-sgen-regular-ms-conc-par-simple-par-dyn-clear-at-gc MONO_TESTS_STRESS=1 || ok=false; \
        $$ok
 
 test-sgen-regular-ms-simple: $(TESTS_SGEN_REGULAR) $(TESTSAOT_SGEN_REGULAR) test-runner.exe
@@ -1452,14 +1452,14 @@ test-sgen-regular-ms-conc-split: $(TESTS_SGEN_REGULAR) $(TESTSAOT_SGEN_REGULAR)
        $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=major=marksweep-conc,minor=split" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_REGULAR)
 test-sgen-regular-ms-conc-split-95-clear-at-gc: $(TESTS_SGEN_REGULAR) $(TESTSAOT_SGEN_REGULAR) test-runner.exe
        $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=clear-at-gc --gc-params=major=marksweep-conc,minor=split,alloc-ratio=95" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_REGULAR)
-test-sgen-regular-ms-conc-par-simple-par: $(TESTS_SGEN_REGULAR) $(TESTSAOT_SGEN_REGULAR) test-runner.exe
-       $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=major=marksweep-conc-par,minor=simple-par" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_REGULAR)
+test-sgen-regular-ms-conc-par-simple-par-dyn: $(TESTS_SGEN_REGULAR) $(TESTSAOT_SGEN_REGULAR) test-runner.exe
+       $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=major=marksweep-conc-par,minor=simple-par,dynamic-nursery" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_REGULAR)
 test-sgen-regular-ms-conc-par-simple-par-512k: $(TESTS_SGEN_REGULAR) $(TESTSAOT_SGEN_REGULAR) test-runner.exe
        $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=major=marksweep-conc-par,minor=simple-par,nursery-size=512k" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_REGULAR)
 test-sgen-regular-ms-conc-par-simple-par-32m: $(TESTS_SGEN_REGULAR) $(TESTSAOT_SGEN_REGULAR) test-runner.exe
        $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=major=marksweep-conc-par,minor=simple-par,nursery-size=32m" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_REGULAR)
-test-sgen-regular-ms-conc-par-simple-par-clear-at-gc: $(TESTS_SGEN_REGULAR) $(TESTSAOT_SGEN_REGULAR) test-runner.exe
-       $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=clear-at-gc --gc-params=major=marksweep-conc-par,minor=simple-par" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_REGULAR)
+test-sgen-regular-ms-conc-par-simple-par-dyn-clear-at-gc: $(TESTS_SGEN_REGULAR) $(TESTSAOT_SGEN_REGULAR) test-runner.exe
+       $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=clear-at-gc --gc-params=major=marksweep-conc-par,minor=simple-par,dynamic-nursery" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_REGULAR)
 
 TESTS_SGEN_TOGGLEREF_SRC=      \
        sgen-toggleref.cs
@@ -1487,10 +1487,10 @@ test-stress-sgen-toggleref: $(TESTS_SGEN_TOGGLEREF) $(TESTSAOT_SGEN_TOGGLEREF)
        $(MAKE) test-sgen-toggleref-ms-conc-par-simple MONO_TESTS_STRESS=1 || ok=false; \
        $(MAKE) test-sgen-toggleref-ms-conc-split MONO_TESTS_STRESS=1 || ok=false; \
        $(MAKE) test-sgen-toggleref-ms-conc-split-95-clear-at-gc MONO_TESTS_STRESS=1 || ok=false; \
-       $(MAKE) test-sgen-toggleref-ms-conc-par-simple-par MONO_TESTS_STRESS=1 || ok=false; \
+       $(MAKE) test-sgen-toggleref-ms-conc-par-simple-par-dyn MONO_TESTS_STRESS=1 || ok=false; \
        $(MAKE) test-sgen-toggleref-ms-conc-par-simple-par-512k MONO_TESTS_STRESS=1 || ok=false; \
        $(MAKE) test-sgen-toggleref-ms-conc-par-simple-par-32m MONO_TESTS_STRESS=1 || ok=false; \
-       $(MAKE) test-sgen-toggleref-ms-conc-par-simple-par-clear-at-gc MONO_TESTS_STRESS=1 || ok=false; \
+       $(MAKE) test-sgen-toggleref-ms-conc-par-simple-par-dyn-clear-at-gc MONO_TESTS_STRESS=1 || ok=false; \
        $$ok
 
 test-sgen-toggleref-ms-simple: $(TESTS_SGEN_TOGGLEREF) $(TESTSAOT_SGEN_TOGGLEREF) test-runner.exe
@@ -1503,14 +1503,14 @@ test-sgen-toggleref-ms-conc-split: $(TESTS_SGEN_TOGGLEREF) $(TESTSAOT_SGEN_TOGGL
        $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=toggleref-test,major=marksweep-conc,minor=split" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_TOGGLEREF)
 test-sgen-toggleref-ms-conc-split-95-clear-at-gc: $(TESTS_SGEN_TOGGLEREF) $(TESTSAOT_SGEN_TOGGLEREF) test-runner.exe
        $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=clear-at-gc --gc-params=toggleref-test,major=marksweep-conc,minor=split,alloc-ratio=95" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_TOGGLEREF)
-test-sgen-toggleref-ms-conc-par-simple-par: $(TESTS_SGEN_TOGGLEREF) $(TESTSAOT_SGEN_TOGGLEREF) test-runner.exe
-       $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=toggleref-test,major=marksweep-conc-par,minor=simple-par" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_TOGGLEREF)
+test-sgen-toggleref-ms-conc-par-simple-par-dyn: $(TESTS_SGEN_TOGGLEREF) $(TESTSAOT_SGEN_TOGGLEREF) test-runner.exe
+       $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=toggleref-test,major=marksweep-conc-par,minor=simple-par,dynamic-nursery" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_TOGGLEREF)
 test-sgen-toggleref-ms-conc-par-simple-par-512k: $(TESTS_SGEN_TOGGLEREF) $(TESTSAOT_SGEN_TOGGLEREF) test-runner.exe
        $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=toggleref-test,major=marksweep-conc-par,minor=simple-par,nursery-size=512k" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_TOGGLEREF)
 test-sgen-toggleref-ms-conc-par-simple-par-32m: $(TESTS_SGEN_TOGGLEREF) $(TESTSAOT_SGEN_TOGGLEREF) test-runner.exe
        $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=toggleref-test,major=marksweep-conc-par,minor=simple-par,nursery-size=32m" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_TOGGLEREF)
-test-sgen-toggleref-ms-conc-par-simple-par-clear-at-gc: $(TESTS_SGEN_TOGGLEREF) $(TESTSAOT_SGEN_TOGGLEREF) test-runner.exe
-       $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=clear-at-gc --gc-params=toggleref-test,major=marksweep-conc-par,minor=simple-par" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_TOGGLEREF)
+test-sgen-toggleref-ms-conc-par-simple-par-dyn-clear-at-gc: $(TESTS_SGEN_TOGGLEREF) $(TESTSAOT_SGEN_TOGGLEREF) test-runner.exe
+       $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=clear-at-gc --gc-params=toggleref-test,major=marksweep-conc-par,minor=simple-par,dynamic-nursery" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_TOGGLEREF)
 
 TESTS_SGEN_BRIDGE_SRC= \
        sgen-bridge.cs  \
@@ -1539,7 +1539,7 @@ test-stress-sgen-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE)
        $(MAKE) test-sgen-bridge-ms-conc-split-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \
        $(MAKE) test-sgen-bridge-ms-conc-simple-new-bridge MONO_TESTS_STRESS=1 || ok=false; \
        $(MAKE) test-sgen-bridge-ms-conc-simple-old-bridge MONO_TESTS_STRESS=1 || ok=false; \
-       $(MAKE) test-sgen-bridge-ms-conc-par-simple-par-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \
+       $(MAKE) test-sgen-bridge-ms-conc-par-simple-par-dyn-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \
        $(MAKE) test-sgen-bridge-ms-conc-par-simple-par-512k-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \
        $(MAKE) test-sgen-bridge-ms-conc-par-simple-par-32m-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \
        $$ok
@@ -1554,28 +1554,13 @@ test-sgen-bridge-ms-conc-simple-new-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN
        $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=Bridge --gc-params=major=marksweep-conc,minor=simple,bridge-implementation=new" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE)
 test-sgen-bridge-ms-conc-simple-old-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) test-runner.exe
        $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=Bridge --gc-params=major=marksweep-conc,minor=simple,bridge-implementation=old" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE)
-test-sgen-bridge-ms-conc-par-simple-par-tarjan-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) test-runner.exe
-       $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=Bridge --gc-params=major=marksweep-conc-par,minor=simple-par,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE)
+test-sgen-bridge-ms-conc-par-simple-par-dyn-tarjan-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) test-runner.exe
+       $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=Bridge --gc-params=major=marksweep-conc-par,minor=simple-par,dynamic-nursery,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE)
 test-sgen-bridge-ms-conc-par-simple-par-512k-tarjan-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) test-runner.exe
        $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=Bridge --gc-params=major=marksweep-conc-par,minor=simple-par,nursery-size=512k,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE)
 test-sgen-bridge-ms-conc-par-simple-par-32m-tarjan-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) test-runner.exe
        $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=Bridge --gc-params=major=marksweep-conc-par,minor=simple-par,nursery-size=32m,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE)
 
-test-sgen-bridge-ms: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) test-runner.exe
-       $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=Bridge --gc-params=" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE)
-test-sgen-bridge-ms-conc: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) test-runner.exe
-       $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=Bridge --gc-params=major=marksweep-conc" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE)
-test-sgen-bridge-ms-new-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) test-runner.exe
-       $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=Bridge --gc-params=bridge-implementation=new" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE)
-test-sgen-bridge-ms-conc-new-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) test-runner.exe
-       $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=Bridge --gc-params=bridge-implementation=new,major=marksweep-conc" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE)
-test-sgen-bridge-ms-split-new-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) test-runner.exe
-       $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=Bridge --gc-params=bridge-implementation=new,minor=split" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE)
-test-sgen-bridge-ms-tarjan-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) test-runner.exe
-       $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=Bridge --gc-params=bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE)
-test-sgen-bridge-ms-split-tarjan-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) test-runner.exe
-       $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=Bridge --gc-params=bridge-implementation=tarjan,minor=split" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE)
-
 TESTS_SGEN_BRIDGE2_SRC=        \
        sgen-bridge-xref.cs
 
@@ -1602,7 +1587,7 @@ test-stress-sgen-bridge2: $(TESTS_SGEN_BRIDGE2) $(TESTSAOT_SGEN_BRIDGE2)
        $(MAKE) test-sgen-bridge2-ms-conc-split-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \
        $(MAKE) test-sgen-bridge2-ms-conc-simple-new-bridge MONO_TESTS_STRESS=1 || ok=false; \
        $(MAKE) test-sgen-bridge2-ms-conc-simple-old-bridge MONO_TESTS_STRESS=1 || ok=false; \
-       $(MAKE) test-sgen-bridge2-ms-conc-par-simple-par-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \
+       $(MAKE) test-sgen-bridge2-ms-conc-par-simple-par-dyn-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \
        $(MAKE) test-sgen-bridge2-ms-conc-par-simple-par-512k-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \
        $(MAKE) test-sgen-bridge2-ms-conc-par-simple-par-32m-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \
        $$ok
@@ -1617,8 +1602,8 @@ test-sgen-bridge2-ms-conc-simple-new-bridge: $(TESTS_SGEN_BRIDGE2) $(TESTSAOT_SG
        $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=2Bridge --gc-params=major=marksweep-conc,minor=simple,bridge-implementation=new" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE2)
 test-sgen-bridge2-ms-conc-simple-old-bridge: $(TESTS_SGEN_BRIDGE2) $(TESTSAOT_SGEN_BRIDGE2) test-runner.exe
        $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=2Bridge --gc-params=major=marksweep-conc,minor=simple,bridge-implementation=old" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE2)
-test-sgen-bridge2-ms-conc-par-simple-par-tarjan-bridge: $(TESTS_SGEN_BRIDGE2) $(TESTSAOT_SGEN_BRIDGE2) test-runner.exe
-       $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=2Bridge --gc-params=major=marksweep-conc-par,minor=simple-par,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE2)
+test-sgen-bridge2-ms-conc-par-simple-par-dyn-tarjan-bridge: $(TESTS_SGEN_BRIDGE2) $(TESTSAOT_SGEN_BRIDGE2) test-runner.exe
+       $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=2Bridge --gc-params=major=marksweep-conc-par,minor=simple-par,dynamic-nursery,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE2)
 test-sgen-bridge2-ms-conc-par-simple-par-512k-tarjan-bridge: $(TESTS_SGEN_BRIDGE2) $(TESTSAOT_SGEN_BRIDGE2) test-runner.exe
        $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=2Bridge --gc-params=major=marksweep-conc-par,minor=simple-par,nursery-size=512k,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE2)
 test-sgen-bridge2-ms-conc-par-simple-par-32m-tarjan-bridge: $(TESTS_SGEN_BRIDGE2) $(TESTSAOT_SGEN_BRIDGE2) test-runner.exe
@@ -1650,7 +1635,7 @@ test-stress-sgen-bridge3: $(TESTS_SGEN_BRIDGE3) $(TESTSAOT_SGEN_BRIDGE3)
        $(MAKE) test-sgen-bridge3-ms-conc-split-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \
        $(MAKE) test-sgen-bridge3-ms-conc-simple-new-bridge MONO_TESTS_STRESS=1 || ok=false; \
        $(MAKE) test-sgen-bridge3-ms-conc-simple-old-bridge MONO_TESTS_STRESS=1 || ok=false; \
-       $(MAKE) test-sgen-bridge3-ms-conc-par-simple-par-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \
+       $(MAKE) test-sgen-bridge3-ms-conc-par-simple-par-dyn-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \
        $(MAKE) test-sgen-bridge3-ms-conc-par-simple-par-512k-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \
        $(MAKE) test-sgen-bridge3-ms-conc-par-simple-par-32m-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \
        $$ok
@@ -1665,8 +1650,8 @@ test-sgen-bridge3-ms-conc-simple-new-bridge: $(TESTS_SGEN_BRIDGE3) $(TESTSAOT_SG
        $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=3Bridge --gc-params=major=marksweep-conc,minor=simple,bridge-implementation=new" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE3)
 test-sgen-bridge3-ms-conc-simple-old-bridge: $(TESTS_SGEN_BRIDGE3) $(TESTSAOT_SGEN_BRIDGE3) test-runner.exe
        $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=3Bridge --gc-params=major=marksweep-conc,minor=simple,bridge-implementation=old" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE3)
-test-sgen-bridge3-ms-conc-par-simple-par-tarjan-bridge: $(TESTS_SGEN_BRIDGE3) $(TESTSAOT_SGEN_BRIDGE3) test-runner.exe
-       $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=3Bridge --gc-params=major=marksweep-conc-par,minor=simple-par,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE3)
+test-sgen-bridge3-ms-conc-par-simple-par-dyn-tarjan-bridge: $(TESTS_SGEN_BRIDGE3) $(TESTSAOT_SGEN_BRIDGE3) test-runner.exe
+       $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=3Bridge --gc-params=major=marksweep-conc-par,minor=simple-par,dynamic-nursery,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE3)
 test-sgen-bridge3-ms-conc-par-simple-par-512k-tarjan-bridge: $(TESTS_SGEN_BRIDGE3) $(TESTSAOT_SGEN_BRIDGE3) test-runner.exe
        $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=3Bridge --gc-params=major=marksweep-conc-par,minor=simple-par,nursery-size=512k,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE3)
 test-sgen-bridge3-ms-conc-par-simple-par-32m-tarjan-bridge: $(TESTS_SGEN_BRIDGE3) $(TESTSAOT_SGEN_BRIDGE3) test-runner.exe