Merge pull request #2803 from BrzVlad/feature-conc-pinned-scan
authormonojenkins <jo.shields+jenkins@xamarin.com>
Thu, 14 Apr 2016 19:15:35 +0000 (20:15 +0100)
committermonojenkins <jo.shields+jenkins@xamarin.com>
Thu, 14 Apr 2016 19:15:35 +0000 (20:15 +0100)
[sgen] Scan pinned objects in nursery as part of concurrent mark

Objects pinned in the nursery can hide behind them a large graph of objects in the heap which is never scanned because we don't follow references in the nursery. After precleaning, we scan the latest set of pinned objects (while locking in order to make sure that the set doesn't change, so none are moved).

mono/sgen/sgen-gc.c
mono/sgen/sgen-pinning.c
mono/sgen/sgen-pinning.h

index e6b8d672dce53fbb73037cc2c4dbfe39bca1a9a7..5ec907371f38451a493b5de735ff26c44620c6cf 100644 (file)
@@ -696,6 +696,8 @@ pin_objects_from_nursery_pin_queue (gboolean do_scan_objects, ScanCopyContext ct
                        definitely_pinned [count] = obj_to_pin;
                        count++;
                }
+               if (concurrent_collection_in_progress)
+                       sgen_pinning_register_pinned_in_nursery (obj_to_pin);
 
        next_pin_queue_entry:
                last = addr;
@@ -1411,6 +1413,8 @@ job_mod_union_preclean (void *worker_data_untyped, SgenThreadPoolJob *job)
 
        major_collector.scan_card_table (CARDTABLE_SCAN_MOD_UNION_PRECLEAN, ctx);
        sgen_los_scan_card_table (CARDTABLE_SCAN_MOD_UNION_PRECLEAN, ctx);
+
+       sgen_scan_pin_queue_objects (ctx);
 }
 
 static void
@@ -3008,6 +3012,7 @@ sgen_gc_init (void)
 
        alloc_nursery ();
 
+       sgen_pinning_init ();
        sgen_cement_init (cement_enabled);
 
        if ((env = g_getenv (MONO_GC_DEBUG_NAME))) {
index eedd1f0343a93e720cac0838ec29ff70e8bd773e..cfe3db1acd0167bd08d1c7e285b6313736460ec3 100644 (file)
 
 static SgenPointerQueue pin_queue;
 static size_t last_num_pinned = 0;
+/*
+ * While we hold the pin_queue_mutex, all objects in pin_queue_objs will
+ * stay pinned, which means they can't move, therefore they can be scanned.
+ */
+static SgenPointerQueue pin_queue_objs;
+static MonoCoopMutex pin_queue_mutex;
 
 #define PIN_HASH_SIZE 1024
 static void *pin_hash_filter [PIN_HASH_SIZE];
 
+void
+sgen_pinning_init (void)
+{
+       mono_coop_mutex_init (&pin_queue_mutex);
+}
+
 void
 sgen_init_pinning (void)
 {
+       mono_coop_mutex_lock (&pin_queue_mutex);
        memset (pin_hash_filter, 0, sizeof (pin_hash_filter));
        pin_queue.mem_type = INTERNAL_MEM_PIN_QUEUE;
+       sgen_pointer_queue_clear (&pin_queue_objs);
 }
 
 void
@@ -37,6 +51,27 @@ sgen_finish_pinning (void)
 {
        last_num_pinned = pin_queue.next_slot;
        sgen_pointer_queue_clear (&pin_queue);
+       mono_coop_mutex_unlock (&pin_queue_mutex);
+}
+
+void
+sgen_pinning_register_pinned_in_nursery (GCObject *obj)
+{
+       sgen_pointer_queue_add (&pin_queue_objs, obj);
+}
+
+void
+sgen_scan_pin_queue_objects (ScanCopyContext ctx)
+{
+       int i;
+       ScanObjectFunc scan_func = ctx.ops->scan_object;
+
+       mono_coop_mutex_lock (&pin_queue_mutex);
+       for (i = 0; i < pin_queue_objs.next_slot; ++i) {
+               GCObject *obj = (GCObject *)pin_queue_objs.data [i];
+               scan_func (obj, sgen_obj_get_descriptor_safe (obj), ctx.queue);
+       }
+       mono_coop_mutex_unlock (&pin_queue_mutex);
 }
 
 void
index 00eb20dd819830f40a45a620981e812426673df2..2ae2594fa85e1c762898e60d43e6caafaf0ed40a 100644 (file)
@@ -18,10 +18,13 @@ enum {
        PIN_TYPE_MAX
 };
 
+void sgen_pinning_init (void);
 void sgen_pin_stage_ptr (void *ptr);
 void sgen_optimize_pin_queue (void);
 void sgen_init_pinning (void);
 void sgen_finish_pinning (void);
+void sgen_pinning_register_pinned_in_nursery (GCObject *obj);
+void sgen_scan_pin_queue_objects (ScanCopyContext ctx);
 void sgen_pin_queue_clear_discarded_entries (GCMemSection *section, size_t max_pin_slot);
 size_t sgen_get_pinned_count (void);
 void sgen_pinning_setup_section (GCMemSection *section);