[sgen] Add CAS object marking for concurrent workers
authorVlad Brezae <brezaevlad@gmail.com>
Mon, 30 May 2016 02:02:17 +0000 (05:02 +0300)
committerVlad Brezae <brezaevlad@gmail.com>
Thu, 19 Jan 2017 22:45:06 +0000 (00:45 +0200)
When marking an object we need to make sure we are not unmarking other objects (since marking is stored as bits). This also allows us to make sure that we never enqueue the same object multiple times on separate gray queues.

mono/sgen/sgen-marksweep-drain-gray-stack.h
mono/sgen/sgen-marksweep.c

index 6a3eb84fc4291b9597fc5fd8766c74ec9c9b4572..787e3f555c0f73ce9d1df6d675f5c2812034d55c 100644 (file)
@@ -174,7 +174,11 @@ COPY_OR_MARK_FUNCTION_NAME (GCObject **ptr, GCObject *obj, SgenGrayQueue *queue)
                        }
 #endif
 
+#ifdef COPY_OR_MARK_PARALLEL
+                       MS_MARK_OBJECT_AND_ENQUEUE_PAR (obj, desc, block, queue);
+#else
                        MS_MARK_OBJECT_AND_ENQUEUE (obj, desc, block, queue);
+#endif
                } else {
                        HEAVY_STAT (++stat_optimized_copy_major_large);
 
index d6c4b66785b3eaf58dac2f7d29a6cfce1c439e5f..72a70c693024ee425ac2b401aae023bc974d2b60 100644 (file)
@@ -134,6 +134,20 @@ typedef struct {
 
 #define MS_MARK_BIT(bl,w,b)    ((bl)->mark_words [(w)] & (ONE_P << (b)))
 #define MS_SET_MARK_BIT(bl,w,b)        ((bl)->mark_words [(w)] |= (ONE_P << (b)))
+#define MS_SET_MARK_BIT_PAR(bl,w,b,first)      do {                    \
+               guint32 tmp_mark_word = (bl)->mark_words [(w)];         \
+               guint32 old_mark_word;                                  \
+               first = FALSE;                                          \
+               while (!(tmp_mark_word & (ONE_P << (b)))) {             \
+                       old_mark_word = tmp_mark_word;                  \
+                       tmp_mark_word = InterlockedCompareExchange ((volatile gint32*)&(bl)->mark_words [w], old_mark_word | (ONE_P << (b)), old_mark_word); \
+                       if (tmp_mark_word == old_mark_word) {           \
+                               first = TRUE;                           \
+                               break;                                  \
+                       }                                               \
+               }                                                       \
+       } while (0)
+
 
 #define MS_OBJ_ALLOCED(o,b)    (*(void**)(o) && (*(char**)(o) < MS_BLOCK_FOR_BLOCK_INFO (b) || *(char**)(o) >= MS_BLOCK_FOR_BLOCK_INFO (b) + MS_BLOCK_SIZE))
 
@@ -1084,6 +1098,21 @@ major_block_is_evacuating (MSBlockInfo *block)
                        INC_NUM_MAJOR_OBJECTS_MARKED ();                \
                }                                                       \
        } while (0)
+#define MS_MARK_OBJECT_AND_ENQUEUE_PAR(obj,desc,block,queue) do {      \
+               int __word, __bit;                                      \
+               gboolean first;                                         \
+               MS_CALC_MARK_BIT (__word, __bit, (obj));                \
+               SGEN_ASSERT (9, MS_OBJ_ALLOCED ((obj), (block)), "object %p not allocated", obj); \
+               MS_SET_MARK_BIT_PAR ((block), __word, __bit, first);    \
+               if (first) {                                            \
+                       if (sgen_gc_descr_has_references (desc))        \
+                               GRAY_OBJECT_ENQUEUE ((queue), (obj), (desc)); \
+                       binary_protocol_mark ((obj), (gpointer)SGEN_LOAD_VTABLE ((obj)), sgen_safe_object_get_size ((obj))); \
+                       INC_NUM_MAJOR_OBJECTS_MARKED ();                \
+               }                                                       \
+       } while (0)
+
+
 
 static void
 pin_major_object (GCObject *obj, SgenGrayQueue *queue)