Use los scanning function for big objects on major heap.
authorRodrigo Kumpera <kumpera@gmail.com>
Fri, 3 Sep 2010 17:03:49 +0000 (14:03 -0300)
committerRodrigo Kumpera <kumpera@gmail.com>
Sat, 4 Sep 2010 20:30:44 +0000 (17:30 -0300)
* sgen-cardtable.c (sgen_cardtable_scan_object): The
source of the cardtable can now be supplied, this is needed
since major blocks can't use regular card checking code here.

* sgen-los.c (los_scan_card_table): Adjust to signature
change in sgen_cardtable_scan_object.

* sgen-marksweep.c (major_scan_card_table): If the block
size is larger than a card it makes more sense to loop
around objects and not cards since objects might be scanned
twice since a card can be shared between two of them.

In such case the cards of a block must be copied to a side
buffer since we are no longer looping one by one. This ia
a problem when two objects share a marked card as the first
can cause it to be left cleared and not have the second one
scanned.

Another advantage of this patch is that it enables partial
scanning of larger array in the major heap.

mono/metadata/sgen-cardtable.c
mono/metadata/sgen-gc.h
mono/metadata/sgen-los.c
mono/metadata/sgen-marksweep.c

index 1b6088e16b022dc395efb9c3eb5a0373009464f5..cef42e04d8cc6068d2e04fd3b7a5f9e8b7ea59e3 100644 (file)
@@ -71,7 +71,7 @@ sgen_card_table_card_begin_scanning (mword address)
        return *sgen_card_table_get_shadow_card_address (address) != 0;
 }
 
-gboolean
+static gboolean
 sgen_card_table_region_begin_scanning (mword start, mword end)
 {
        while (start <= end) {
@@ -82,6 +82,12 @@ sgen_card_table_region_begin_scanning (mword start, mword end)
        return FALSE;
 }
 
+void
+sgen_card_table_get_card_data (guint8 *dest, mword address, mword cards)
+{
+       memcpy (dest, sgen_card_table_get_shadow_card_address (address), cards);
+}
+
 #else
 
 guint8*
@@ -99,7 +105,7 @@ sgen_card_table_card_begin_scanning (mword address)
        return res;
 }
 
-gboolean
+static gboolean
 sgen_card_table_region_begin_scanning (mword start, mword size)
 {
        gboolean res = FALSE;
@@ -118,6 +124,15 @@ sgen_card_table_region_begin_scanning (mword start, mword size)
        return res;
 }
 
+void
+sgen_card_table_get_card_data (guint8 *dest, mword address, mword cards)
+{
+       int i;
+       guint8 *src = sgen_card_table_get_card_address (address);
+       memcpy (dest, src, cards);
+       memset (src, 0, cards);
+}
+
 #endif
 
 static gboolean
@@ -148,6 +163,19 @@ sgen_card_table_mark_range (mword address, mword size)
        } while (address < end);
 }
 
+static gboolean
+sgen_card_table_is_range_marked (guint8 *cards, mword size)
+{
+       mword start = 0;
+       while (start <= size) {
+               if (*cards++)
+                       return TRUE;
+               start += CARD_SIZE_IN_BYTES;
+       }
+       return FALSE;
+
+}
+
 static void
 card_table_init (void)
 {
@@ -243,7 +271,7 @@ collect_faulted_cards (void)
 
 
 void
-sgen_cardtable_scan_object (char *obj, mword obj_size, SgenGrayQueue *queue)
+sgen_cardtable_scan_object (char *obj, mword obj_size, guint8 *cards, SgenGrayQueue *queue)
 {
        MonoVTable *vt = (MonoVTable*)LOAD_VTABLE (obj);
        MonoClass *klass = vt->klass;
@@ -264,8 +292,12 @@ sgen_cardtable_scan_object (char *obj, mword obj_size, SgenGrayQueue *queue)
                        char *elem, *card_end;
                        uintptr_t index;
 
-                       if (!sgen_card_table_card_begin_scanning ((mword)start))
+                       if (cards) {
+                               if (!*cards++)
+                                       continue;
+                       } else if (!sgen_card_table_card_begin_scanning ((mword)start)) {
                                continue;
+                       }
 
                        card_end = start + CARD_SIZE_IN_BYTES;
                        if (end < card_end)
@@ -296,8 +328,12 @@ sgen_cardtable_scan_object (char *obj, mword obj_size, SgenGrayQueue *queue)
                        }
                }
        } else {
-               if (sgen_card_table_region_begin_scanning ((mword)obj, obj_size))
+               if (cards) {
+                       if (sgen_card_table_is_range_marked (cards, obj_size))
+                               major.minor_scan_object (obj, queue);
+               } else if (sgen_card_table_region_begin_scanning ((mword)obj, obj_size)) {
                        major.minor_scan_object (obj, queue);
+               }
        }
 }
 
index 9f93595079fa779e22ef7dbc73ee819aeabe5146..a601769c141e4278b7991b781404ce23d6318ecb 100644 (file)
@@ -660,8 +660,8 @@ void* sgen_card_table_align_pointer (void *ptr) MONO_INTERNAL;
 void sgen_card_table_mark_address (mword address) MONO_INTERNAL;
 void sgen_card_table_mark_range (mword address, mword size) MONO_INTERNAL;
 gboolean sgen_card_table_card_begin_scanning (mword address) MONO_INTERNAL;
-gboolean sgen_card_table_region_begin_scanning (mword start, mword size) MONO_INTERNAL;
-void sgen_cardtable_scan_object (char *obj, mword obj_size, SgenGrayQueue *queue) MONO_INTERNAL;
+void sgen_cardtable_scan_object (char *obj, mword obj_size, guint8 *cards, SgenGrayQueue *queue) MONO_INTERNAL;
+void sgen_card_table_get_card_data (guint8 *dest, mword address, mword cards) MONO_INTERNAL;
 typedef void (*sgen_cardtable_block_callback) (mword start, mword size);
 
 #define CARD_BITS 9
index 7cc3ffb264fe4d02079cd0f21d9dfbb6b115ddc0..b73a99d03235eafe67a8dfec09316bbc90dab221 100644 (file)
@@ -472,7 +472,7 @@ los_scan_card_table (GrayQueue *queue)
        LOSObject *obj;
 
        for (obj = los_object_list; obj; obj = obj->next) {
-               sgen_cardtable_scan_object (obj->data, obj->size, queue);
+               sgen_cardtable_scan_object (obj->data, obj->size, NULL, queue);
        }
 }
 
index d2f8b9c7a56bf709de7241c81abf5088bfec3a0a..4ed99ad9b56c8419f809666b0aff48c190b5db57 100644 (file)
@@ -1264,25 +1264,42 @@ major_scan_card_table (SgenGrayQueue *queue)
                block_obj_size = block->obj_size;
                start = block->block;
 
-               for (i = 0; i < CARDS_PER_BLOCK; ++i, start += CARD_SIZE_IN_BYTES) {
-                       int index;
-                       char *obj, *end;
+               if (block_obj_size >= CARD_SIZE_IN_BYTES) {
+                       guint8 cards [CARDS_PER_BLOCK];
+                       char *obj = (char*)MS_BLOCK_OBJ (block, 0);
+                       char *end = start + MS_BLOCK_SIZE;
+                       char *base = sgen_card_table_align_pointer (obj);
 
-                       if (!sgen_card_table_card_begin_scanning ((mword)start))
-                               continue;
+                       sgen_card_table_get_card_data (cards, (mword)start, CARDS_PER_BLOCK);
 
-                       end = start + CARD_SIZE_IN_BYTES;
-                       if (i == 0)
-                               index = 0;
-                       else
-                               index = MS_BLOCK_OBJ_INDEX (start, block);
-
-                       obj = (char*)MS_BLOCK_OBJ (block, index);
                        while (obj < end) {
-                               if (MS_OBJ_ALLOCED (obj, block))
-                                       minor_scan_object (obj, queue);
+                               if (MS_OBJ_ALLOCED (obj, block)) {
+                                       int card_offset = (obj - base) >> CARD_BITS;
+                                       sgen_cardtable_scan_object (obj, block_obj_size, cards + card_offset, queue);
+                               }
                                obj += block_obj_size;
                        }
+               } else {
+                       for (i = 0; i < CARDS_PER_BLOCK; ++i, start += CARD_SIZE_IN_BYTES) {
+                               int index;
+                               char *obj, *end;
+
+                               if (!sgen_card_table_card_begin_scanning ((mword)start))
+                                       continue;
+
+                               end = start + CARD_SIZE_IN_BYTES;
+                               if (i == 0)
+                                       index = 0;
+                               else
+                                       index = MS_BLOCK_OBJ_INDEX (start, block);
+
+                               obj = (char*)MS_BLOCK_OBJ (block, index);
+                               while (obj < end) {
+                                       if (MS_OBJ_ALLOCED (obj, block))
+                                               minor_scan_object (obj, queue);
+                                       obj += block_obj_size;
+                               }
+                       }
                }
        } END_FOREACH_BLOCK;
 }