[sgen] Scan pinned objects in nursery as part of concurrent mark
authorVlad Brezae <brezaevlad@gmail.com>
Wed, 23 Mar 2016 19:16:34 +0000 (21:16 +0200)
committerVlad Brezae <brezaevlad@gmail.com>
Thu, 14 Apr 2016 14:26:17 +0000 (17:26 +0300)
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 2274febcb108a57359ff380aec845c0554feb08f..d9bc6485945160ff79c0fa85b20e1cddb4c10e4b 100644 (file)
@@ -708,6 +708,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;
@@ -1419,6 +1421,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
@@ -3016,6 +3020,7 @@ sgen_gc_init (void)
 
        alloc_nursery ();
 
+       sgen_pinning_init ();
        sgen_cement_init (cement_enabled);
 
        if ((env = g_getenv (MONO_GC_DEBUG_NAME))) {
index 4ed5d0a6b5b879bdc0788d1b0b4ac50f0a0973b6..85629f436ec46189ebd1aa7d8b30e8efdc9ad8c4 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
@@ -48,6 +62,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 50d0f966ac046cba52c326989a1d77c492843f0a..92143c6ee60756871b3c0a3cf346b10a68349ab5 100644 (file)
@@ -29,10 +29,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);