[sgen] More information in sweep and world restart DTrace probes.
[mono.git] / mono / metadata / sgen-marksweep.c
index 1a4a623404ec20db0cd7665ca44c5b5004f2616c..db3de651bb377f3cf0d9b15dafc4066ce343c10b 100644 (file)
@@ -93,6 +93,9 @@ struct _MSBlockInfo {
        void **free_list;
        MSBlockInfo *next_free;
        void **pin_queue_start;
+#ifdef SGEN_CONCURRENT_MARK
+       guint8 *cardtable_mod_union;
+#endif
        mword mark_words [MS_NUM_MARK_WORDS];
 };
 
@@ -578,6 +581,9 @@ ms_alloc_block (int size_index, gboolean pinned, gboolean has_references)
        header = (MSBlockHeader*) info->block;
        header->info = info;
 #endif
+#ifdef SGEN_CONCURRENT_MARK
+       info->cardtable_mod_union = NULL;
+#endif
 
        update_heap_boundaries_for_block (info);
 
@@ -673,7 +679,7 @@ try_remove_block_from_free_list (MSBlockInfo *block, MSBlockInfo **free_blocks,
 }
 
 static void*
-alloc_obj_par (int size, gboolean pinned, gboolean has_references)
+alloc_obj_par (MonoVTable *vtable, int size, gboolean pinned, gboolean has_references)
 {
        int size_index = MS_BLOCK_OBJ_SIZE_INDEX (size);
        MSBlockInfo **free_blocks_local = FREE_BLOCKS_LOCAL (pinned, has_references);
@@ -715,24 +721,24 @@ alloc_obj_par (int size, gboolean pinned, gboolean has_references)
                }
        }
 
-       /*
-        * FIXME: This should not be necessary because it'll be
-        * overwritten by the vtable immediately.
-        */
-       *(void**)obj = NULL;
+       *(MonoVTable**)obj = vtable;
+
+#ifdef SGEN_CONCURRENT_MARK
+       g_assert_not_reached ();
+#endif
 
        return obj;
 }
 
 static void*
-major_par_alloc_object (int size, gboolean has_references)
+major_par_alloc_object (MonoVTable *vtable, int size, gboolean has_references)
 {
-       return alloc_obj_par (size, FALSE, has_references);
+       return alloc_obj_par (vtable, size, FALSE, has_references);
 }
 #endif
 
 static void*
-alloc_obj (int size, gboolean pinned, gboolean has_references)
+alloc_obj (MonoVTable *vtable, int size, gboolean pinned, gboolean has_references)
 {
        int size_index = MS_BLOCK_OBJ_SIZE_INDEX (size);
        MSBlockInfo **free_blocks = FREE_BLOCKS (pinned, has_references);
@@ -752,19 +758,25 @@ alloc_obj (int size, gboolean pinned, gboolean has_references)
 
        obj = unlink_slot_from_free_list_uncontested (free_blocks, size_index);
 
-       /*
-        * FIXME: This should not be necessary because it'll be
-        * overwritten by the vtable immediately.
-        */
-       *(void**)obj = NULL;
+       *(MonoVTable**)obj = vtable;
+
+#ifdef SGEN_CONCURRENT_MARK
+       if (obj && sgen_remember_major_object_for_concurrent_mark (obj)) {
+               MSBlockInfo *block = MS_BLOCK_FOR_OBJ (obj);
+               int word, bit;
+               MS_CALC_MARK_BIT (word, bit, obj);
+               MS_SET_MARK_BIT (block, word, bit);
+               binary_protocol_mark (obj, NULL, size);
+       }
+#endif
 
        return obj;
 }
 
 static void*
-major_alloc_object (int size, gboolean has_references)
+major_alloc_object (MonoVTable *vtable, int size, gboolean has_references)
 {
-       return alloc_obj (size, FALSE, has_references);
+       return alloc_obj (vtable, size, FALSE, has_references);
 }
 
 /*
@@ -806,19 +818,19 @@ major_free_non_pinned_object (char *obj, size_t size)
 
 /* size is a multiple of SGEN_ALLOC_ALIGN */
 static void*
-major_alloc_small_pinned_obj (size_t size, gboolean has_references)
+major_alloc_small_pinned_obj (MonoVTable *vtable, size_t size, gboolean has_references)
 {
        void *res;
 
        ms_wait_for_sweep_done ();
 
-       res = alloc_obj (size, TRUE, has_references);
+       res = alloc_obj (vtable, size, TRUE, has_references);
         /*If we failed to alloc memory, we better try releasing memory
          *as pinned alloc is requested by the runtime.
          */
         if (!res) {
-               sgen_perform_collection (0, GENERATION_OLD, "pinned alloc failure");
-               res = alloc_obj (size, TRUE, has_references);
+               sgen_perform_collection (0, GENERATION_OLD, "pinned alloc failure", TRUE);
+               res = alloc_obj (vtable, size, TRUE, has_references);
         }
         return res;
 }
@@ -842,9 +854,8 @@ major_alloc_degraded (MonoVTable *vtable, size_t size)
 
        old_num_sections = num_major_sections;
 
-       obj = alloc_obj (size, FALSE, SGEN_VTABLE_HAS_REFERENCES (vtable));
+       obj = alloc_obj (vtable, size, FALSE, SGEN_VTABLE_HAS_REFERENCES (vtable));
        if (G_LIKELY (obj)) {
-               *(MonoVTable**)obj = vtable;
                HEAVY_STAT (++stat_objects_alloced_degraded);
                HEAVY_STAT (stat_bytes_alloced_degraded += size);
                g_assert (num_major_sections >= old_num_sections);
@@ -1103,9 +1114,13 @@ major_dump_heap (FILE *heap_dump_file)
 static void
 pin_major_object (char *obj, SgenGrayQueue *queue)
 {
+#ifdef SGEN_CONCURRENT_MARK
+       g_assert_not_reached ();
+#else
        MSBlockInfo *block = MS_BLOCK_FOR_OBJ (obj);
        block->has_pinned = TRUE;
        MS_MARK_OBJECT_AND_ENQUEUE (obj, block, queue);
+#endif
 }
 
 #include "sgen-major-copy-object.h"
@@ -1149,7 +1164,7 @@ major_copy_or_mark_object (void **ptr, SgenGrayQueue *queue)
                objsize = SGEN_ALIGN_UP (sgen_par_object_get_size (vt, (MonoObject*)obj));
                has_references = SGEN_VTABLE_HAS_REFERENCES (vt);
 
-               destination = sgen_minor_collector.par_alloc_for_promotion (obj, objsize, has_references);
+               destination = sgen_minor_collector.par_alloc_for_promotion (vt, obj, objsize, has_references);
                if (G_UNLIKELY (!destination)) {
                        if (!sgen_ptr_in_nursery (obj)) {
                                int size_index;
@@ -1163,14 +1178,6 @@ major_copy_or_mark_object (void **ptr, SgenGrayQueue *queue)
                        return;
                }
 
-               /*
-                * We do this before the CAS because we want to make
-                * sure that if another thread sees the destination
-                * pointer the VTable is already in place.  Not doing
-                * this can crash binary protocols.
-                */
-               *(MonoVTable**)destination = vt;
-
                if (SGEN_CAS_PTR (obj, (void*)((mword)destination | SGEN_FORWARDED_BIT), vt) == vt) {
                        gboolean was_marked;
 
@@ -1283,7 +1290,7 @@ major_copy_or_mark_object (void **ptr, SgenGrayQueue *queue)
        g_assert (!SGEN_OBJECT_IS_FORWARDED (obj));
 
        if (sgen_ptr_in_nursery (obj)) {
-               g_assert (SGEN_OBJECT_IS_PINNED (obj));
+               g_assert (!SGEN_OBJECT_IS_PINNED (obj));
        } else {
 #ifdef FIXED_HEAP
                if (MS_PTR_IN_SMALL_MAJOR_HEAP (obj))
@@ -1300,7 +1307,6 @@ major_copy_or_mark_object (void **ptr, SgenGrayQueue *queue)
                } else {
                        if (sgen_los_object_is_pinned (obj))
                                return;
-                       binary_protocol_pin (obj, (gpointer)SGEN_LOAD_VTABLE (obj), sgen_safe_object_get_size ((MonoObject*)obj));
                        if (G_UNLIKELY (MONO_GC_OBJ_PINNED_ENABLED ())) {
                                MonoVTable *vt = (MonoVTable*)SGEN_LOAD_VTABLE (obj);
                                MONO_GC_OBJ_PINNED ((mword)obj, sgen_safe_object_get_size (obj), vt->klass->name_space, vt->klass->name, GENERATION_OLD);
@@ -1604,6 +1610,13 @@ ms_sweep (void)
 
                count = MS_BLOCK_FREE / block->obj_size;
 
+#ifdef SGEN_CONCURRENT_MARK
+               if (block->cardtable_mod_union) {
+                       sgen_free_internal_dynamic (block->cardtable_mod_union, CARDS_PER_BLOCK, INTERNAL_MEM_CARDTABLE_MOD_UNION);
+                       block->cardtable_mod_union = NULL;
+               }
+#endif
+
                /* Count marked objects in the block */
                for (i = 0; i < MS_NUM_MARK_WORDS; ++i) {
                        nused += bitcount (block->mark_words [i]);
@@ -1820,6 +1833,8 @@ major_start_major_collection (void)
        if (lazy_sweep) {
                MSBlockInfo **iter;
 
+               MONO_GC_SWEEP_BEGIN (GENERATION_OLD, TRUE);
+
                iter = &all_blocks;
                while (*iter) {
                        MSBlockInfo *block = *iter;
@@ -1828,6 +1843,8 @@ major_start_major_collection (void)
 
                        iter = &block->next;
                }
+
+               MONO_GC_SWEEP_END (GENERATION_OLD, TRUE);
        }
 }
 
@@ -2040,7 +2057,7 @@ skip_card (guint8 *card_data, guint8 *card_data_end)
 #define MS_OBJ_ALLOCED_FAST(o,b)               (*(void**)(o) && (*(char**)(o) < (b) || *(char**)(o) >= (b) + MS_BLOCK_SIZE))
 
 static void
-major_scan_card_table (SgenGrayQueue *queue)
+major_scan_card_table (gboolean mod_union, SgenGrayQueue *queue)
 {
        MSBlockInfo *block;
        ScanObjectFunc scan_func = sgen_get_current_object_ops ()->scan_object;
@@ -2062,14 +2079,23 @@ major_scan_card_table (SgenGrayQueue *queue)
 #endif
                        char *obj, *end, *base;
 
+                       if (mod_union) {
+#ifdef SGEN_CONCURRENT_MARK
+                               cards = block->cardtable_mod_union;
+                               g_assert (cards);
+#else
+                               g_assert_not_reached ();
+#endif
+                       } else {
                        /*We can avoid the extra copy since the remark cardtable was cleaned before */
 #ifdef SGEN_HAVE_OVERLAPPING_CARDS
-                       cards = sgen_card_table_get_card_scan_address ((mword)block_start);
+                               cards = sgen_card_table_get_card_scan_address ((mword)block_start);
 #else
-                       cards = cards_data;
-                       if (!sgen_card_table_get_card_data (cards_data, (mword)block_start, CARDS_PER_BLOCK))
-                               continue;
+                               cards = cards_data;
+                               if (!sgen_card_table_get_card_data (cards_data, (mword)block_start, CARDS_PER_BLOCK))
+                                       continue;
 #endif
+                       }
 
                        if (!block->swept)
                                sweep_block (block);
@@ -2079,10 +2105,23 @@ major_scan_card_table (SgenGrayQueue *queue)
                        base = sgen_card_table_align_pointer (obj);
 
                        while (obj < end) {
-                               if (MS_OBJ_ALLOCED_FAST (obj, block_start)) {
-                                       int card_offset = (obj - base) >> CARD_BITS;
-                                       sgen_cardtable_scan_object (obj, block_obj_size, cards + card_offset, queue);
+                               int card_offset;
+
+                               if (!MS_OBJ_ALLOCED_FAST (obj, block_start))
+                                       goto next_large;
+
+                               if (mod_union) {
+                                       /* FIXME: do this more efficiently */
+                                       int w, b;
+                                       MS_CALC_MARK_BIT (w, b, obj);
+                                       if (!MS_MARK_BIT (block, w, b))
+                                               goto next_large;
                                }
+
+                               card_offset = (obj - base) >> CARD_BITS;
+                               sgen_cardtable_scan_object (obj, block_obj_size, cards + card_offset, queue);
+
+                       next_large:
                                obj += block_obj_size;
                        }
                } else {
@@ -2096,7 +2135,23 @@ major_scan_card_table (SgenGrayQueue *queue)
                         * Cards aliasing happens in powers of two, so as long as major blocks are aligned to their
                         * sizes, they won't overflow the cardtable overlap modulus.
                         */
-                       card_data = card_base = sgen_card_table_get_card_scan_address ((mword)block_start);
+                       if (mod_union) {
+#ifdef SGEN_CONCURRENT_MARK
+                               card_data = card_base = block->cardtable_mod_union;
+                               /*
+                                * This happens when the nursery
+                                * collection that precedes finishing
+                                * the concurrent collection allocates
+                                * new major blocks.
+                                */
+                               if (!card_data)
+                                       continue;
+#else
+                               g_assert_not_reached ();
+#endif
+                       } else {
+                               card_data = card_base = sgen_card_table_get_card_scan_address ((mword)block_start);
+                       }
                        card_data_end = card_data + CARDS_PER_BLOCK;
 
                        for (card_data = initial_skip_card (card_data); card_data < card_data_end; ++card_data) { //card_data = skip_card (card_data + 1, card_data_end)) {
@@ -2125,10 +2180,20 @@ major_scan_card_table (SgenGrayQueue *queue)
 
                                obj = (char*)MS_BLOCK_OBJ_FAST (block_start, block_obj_size, index);
                                while (obj < end) {
-                                       if (MS_OBJ_ALLOCED_FAST (obj, block_start)) {
-                                               HEAVY_STAT (++scanned_objects);
-                                               scan_func (obj, queue);
+                                       if (!MS_OBJ_ALLOCED_FAST (obj, block_start))
+                                               goto next_small;
+
+                                       if (mod_union) {
+                                               /* FIXME: do this more efficiently */
+                                               int w, b;
+                                               MS_CALC_MARK_BIT (w, b, obj);
+                                               if (!MS_MARK_BIT (block, w, b))
+                                                       goto next_small;
                                        }
+
+                                       HEAVY_STAT (++scanned_objects);
+                                       scan_func (obj, queue);
+                               next_small:
                                        obj += block_obj_size;
                                }
                                HEAVY_STAT (if (*card_data) ++remarked_cards);
@@ -2136,6 +2201,34 @@ major_scan_card_table (SgenGrayQueue *queue)
                }
        } END_FOREACH_BLOCK;
 }
+
+#ifdef SGEN_CONCURRENT_MARK
+static void
+update_cardtable_mod_union (void)
+{
+       MSBlockInfo *block;
+
+       FOREACH_BLOCK (block) {
+               guint8 *cards;
+               gboolean init = FALSE;
+
+               if (!block->cardtable_mod_union) {
+                       block->cardtable_mod_union = sgen_alloc_internal_dynamic (CARDS_PER_BLOCK,
+                                       INTERNAL_MEM_CARDTABLE_MOD_UNION, TRUE);
+                       init = TRUE;
+               }
+
+               cards = sgen_card_table_get_card_scan_address ((mword)block->block);
+               if (init) {
+                       memcpy (block->cardtable_mod_union, cards, CARDS_PER_BLOCK);
+               } else {
+                       int i;
+                       for (i = 0; i < CARDS_PER_BLOCK; ++i)
+                               block->cardtable_mod_union [i] |= cards [i];
+               }
+       } END_FOREACH_BLOCK;
+}
+#endif
 #endif
 
 static gboolean
@@ -2201,7 +2294,7 @@ major_reset_worker_data (void *data)
 #undef pthread_create
 
 static void
-post_param_init (void)
+post_param_init (SgenMajorCollector *collector)
 {
        if (concurrent_sweep) {
                if (!mono_native_thread_create (&ms_sweep_thread, ms_sweep_thread_func, NULL)) {
@@ -2209,6 +2302,8 @@ post_param_init (void)
                        exit (1);
                }
        }
+
+       collector->sweeps_lazily = lazy_sweep;
 }
 
 void
@@ -2319,6 +2414,9 @@ sgen_marksweep_init
 #ifdef SGEN_HAVE_CARDTABLE
        collector->scan_card_table = major_scan_card_table;
        collector->iterate_live_block_ranges = (void*)(void*) major_iterate_live_block_ranges;
+#ifdef SGEN_CONCURRENT_MARK
+       collector->update_cardtable_mod_union = update_cardtable_mod_union;
+#endif
 #endif
        collector->init_to_space = major_init_to_space;
        collector->sweep = major_sweep;
@@ -2343,6 +2441,9 @@ sgen_marksweep_init
 
        collector->major_ops.copy_or_mark_object = major_copy_or_mark_object;
        collector->major_ops.scan_object = major_scan_object;
+#ifdef SGEN_CONCURRENT_MARK
+       collector->major_ops.scan_vtype = major_scan_vtype;
+#endif
 
 #ifdef SGEN_HAVE_CARDTABLE
        /*cardtable requires major pages to be 8 cards aligned*/