Merge pull request #2803 from BrzVlad/feature-conc-pinned-scan
[mono.git] / mono / sgen / sgen-cardtable.c
index 21da2d0df848ba32e69c2126d1d8d9fb3ffeee3e..05dfe7d90743b041f12bcf26d587213920fe46c0 100644 (file)
@@ -9,18 +9,7 @@
  * 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;
- *
- * 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.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
 #include "config.h"
@@ -86,8 +75,8 @@ sgen_card_table_wbarrier_set_field (GCObject *obj, gpointer field_ptr, GCObject*
 static void
 sgen_card_table_wbarrier_arrayref_copy (gpointer dest_ptr, gpointer src_ptr, int count)
 {
-       gpointer *dest = dest_ptr;
-       gpointer *src = src_ptr;
+       gpointer *dest = (gpointer *)dest_ptr;
+       gpointer *src = (gpointer *)src_ptr;
 
        /*overlapping that required backward copying*/
        if (src < dest && (src + count) > dest) {
@@ -119,19 +108,13 @@ sgen_card_table_wbarrier_value_copy (gpointer dest, gpointer src, int count, siz
 {
        size_t size = count * element_size;
 
-#ifdef DISABLE_CRITICAL_REGION
-       LOCK_GC;
-#else
        TLAB_ACCESS_INIT;
        ENTER_CRITICAL_REGION;
-#endif
+
        mono_gc_memmove_atomic (dest, src, size);
        sgen_card_table_mark_range ((mword)dest, size);
-#ifdef DISABLE_CRITICAL_REGION
-       UNLOCK_GC;
-#else
+
        EXIT_CRITICAL_REGION;
-#endif
 }
 
 static void
@@ -139,20 +122,14 @@ sgen_card_table_wbarrier_object_copy (GCObject* obj, GCObject *src)
 {
        size_t size = sgen_client_par_object_get_size (SGEN_LOAD_VTABLE_UNCHECKED (obj), obj);
 
-#ifdef DISABLE_CRITICAL_REGION
-       LOCK_GC;
-#else
        TLAB_ACCESS_INIT;
        ENTER_CRITICAL_REGION;
-#endif
+
        mono_gc_memmove_aligned ((char*)obj + SGEN_CLIENT_OBJECT_HEADER_SIZE, (char*)src + SGEN_CLIENT_OBJECT_HEADER_SIZE,
                        size - SGEN_CLIENT_OBJECT_HEADER_SIZE);
        sgen_card_table_mark_range ((mword)obj, size);
-#ifdef DISABLE_CRITICAL_REGION
-       UNLOCK_GC;
-#else
+
        EXIT_CRITICAL_REGION;
-#endif 
 }
 
 static void
@@ -284,7 +261,7 @@ sgen_card_table_find_address (char *addr)
 static gboolean
 sgen_card_table_find_address_with_cards (char *cards_start, guint8 *cards, char *addr)
 {
-       cards_start = sgen_card_table_align_pointer (cards_start);
+       cards_start = (char *)sgen_card_table_align_pointer (cards_start);
        return cards [(addr - cards_start) >> CARD_BITS];
 }
 
@@ -292,15 +269,18 @@ static void
 update_mod_union (guint8 *dest, guint8 *start_card, size_t num_cards)
 {
        int i;
-       for (i = 0; i < num_cards; ++i)
-               dest [i] |= start_card [i];
+       /* Marking from another thread can happen while we mark here */
+       for (i = 0; i < num_cards; ++i) {
+               if (start_card [i])
+                       dest [i] = 1;
+       }
 }
 
 guint8*
 sgen_card_table_alloc_mod_union (char *obj, mword obj_size)
 {
        size_t num_cards = sgen_card_table_number_of_cards_in_range ((mword) obj, obj_size);
-       guint8 *mod_union = sgen_alloc_internal_dynamic (num_cards, INTERNAL_MEM_CARDTABLE_MOD_UNION, TRUE);
+       guint8 *mod_union = (guint8 *)sgen_alloc_internal_dynamic (num_cards, INTERNAL_MEM_CARDTABLE_MOD_UNION, TRUE);
        memset (mod_union, 0, num_cards);
        return mod_union;
 }
@@ -351,6 +331,29 @@ sgen_card_table_update_mod_union (guint8 *dest, char *obj, mword obj_size, size_
                *out_num_cards = num_cards;
 }
 
+/* Preclean cards and saves the cards that need to be scanned afterwards in cards_preclean */
+void
+sgen_card_table_preclean_mod_union (guint8 *cards, guint8 *cards_preclean, size_t num_cards)
+{
+       size_t i;
+
+       memcpy (cards_preclean, cards, num_cards);
+       for (i = 0; i < num_cards; i++) {
+               if (cards_preclean [i]) {
+                       cards [i] = 0;
+               }
+       }
+       /*
+        * When precleaning we need to make sure the card cleaning
+        * takes place before the object is scanned. If we don't
+        * do this we could finish scanning the object and, before
+        * the cleaning of the card takes place, another thread
+        * could dirty the object, mark the mod_union card only for
+        * us to clean it back, without scanning the object again.
+        */
+       mono_memory_barrier ();
+}
+
 #ifdef SGEN_HAVE_OVERLAPPING_CARDS
 
 static void
@@ -435,11 +438,11 @@ sgen_card_table_scan_remsets (ScanCopyContext ctx)
        sgen_card_table_clear_cards ();
 #endif
        SGEN_TV_GETTIME (atv);
-       sgen_get_major_collector ()->scan_card_table (FALSE, ctx);
+       sgen_get_major_collector ()->scan_card_table (CARDTABLE_SCAN_GLOBAL, ctx);
        SGEN_TV_GETTIME (btv);
        last_major_scan_time = SGEN_TV_ELAPSED (atv, btv); 
        major_card_scan_time += last_major_scan_time;
-       sgen_los_scan_card_table (FALSE, ctx);
+       sgen_los_scan_card_table (CARDTABLE_SCAN_GLOBAL, ctx);
        SGEN_TV_GETTIME (atv);
        last_los_scan_time = SGEN_TV_ELAPSED (btv, atv);
        los_card_scan_time += last_los_scan_time;
@@ -486,11 +489,11 @@ sgen_card_table_dump_obj_card (GCObject *object, size_t size, void *dummy)
 #endif
 
 void
-sgen_cardtable_scan_object (GCObject *obj, mword block_obj_size, guint8 *cards, gboolean mod_union, ScanCopyContext ctx)
+sgen_cardtable_scan_object (GCObject *obj, mword block_obj_size, guint8 *cards, ScanCopyContext ctx)
 {
        HEAVY_STAT (++large_objects);
 
-       if (sgen_client_cardtable_scan_object (obj, block_obj_size, cards, mod_union, ctx))
+       if (sgen_client_cardtable_scan_object (obj, block_obj_size, cards, ctx))
                return;
 
        HEAVY_STAT (++bloby_objects);
@@ -570,10 +573,10 @@ sgen_card_tables_collect_stats (gboolean begin)
 void
 sgen_card_table_init (SgenRememberedSet *remset)
 {
-       sgen_cardtable = sgen_alloc_os_memory (CARD_COUNT_IN_BYTES, SGEN_ALLOC_INTERNAL | SGEN_ALLOC_ACTIVATE, "card table");
+       sgen_cardtable = (guint8 *)sgen_alloc_os_memory (CARD_COUNT_IN_BYTES, (SgenAllocFlags)(SGEN_ALLOC_INTERNAL | SGEN_ALLOC_ACTIVATE), "card table");
 
 #ifdef SGEN_HAVE_OVERLAPPING_CARDS
-       sgen_shadow_cardtable = sgen_alloc_os_memory (CARD_COUNT_IN_BYTES, SGEN_ALLOC_INTERNAL | SGEN_ALLOC_ACTIVATE, "shadow card table");
+       sgen_shadow_cardtable = (guint8 *)sgen_alloc_os_memory (CARD_COUNT_IN_BYTES, (SgenAllocFlags)(SGEN_ALLOC_INTERNAL | SGEN_ALLOC_ACTIVATE), "shadow card table");
 #endif
 
 #ifdef HEAVY_STATISTICS