Author: Armin Rigo <ar...@tunes.org>
Branch: marker
Changeset: r1180:3cdcd273d6d3
Date: 2014-04-23 17:01 +0200
http://bitbucket.org/pypy/stmgc/changeset/3cdcd273d6d3/

Log:    in-progress: record markers corresponding to old_modified_objects

diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -86,6 +86,13 @@
            Add it to the list 'modified_old_objects'. */
         LIST_APPEND(STM_PSEGMENT->modified_old_objects, obj);
 
+        /* Add the current marker, recording where we wrote to this object */
+        uintptr_t marker[2];
+        marker_fetch(STM_SEGMENT->running_thread, marker);
+        STM_PSEGMENT->modified_old_objects_markers =
+            list_append2(STM_PSEGMENT->modified_old_objects_markers,
+                         marker[0], marker[1]);
+
         /* We need to privatize the pages containing the object, if they
            are still SHARED_PAGE.  The common case is that there is only
            one page in total. */
@@ -223,12 +230,17 @@
     }
 
     assert(list_is_empty(STM_PSEGMENT->modified_old_objects));
+    assert(list_is_empty(STM_PSEGMENT->modified_old_objects_markers));
     assert(list_is_empty(STM_PSEGMENT->young_weakrefs));
     assert(tree_is_cleared(STM_PSEGMENT->young_outside_nursery));
     assert(tree_is_cleared(STM_PSEGMENT->nursery_objects_shadows));
     assert(tree_is_cleared(STM_PSEGMENT->callbacks_on_abort));
     assert(STM_PSEGMENT->objects_pointing_to_nursery == NULL);
     assert(STM_PSEGMENT->large_overflow_objects == NULL);
+#ifndef NDEBUG
+    /* this should not be used when objects_pointing_to_nursery == NULL */
+    STM_PSEGMENT->modified_old_objects_markers_num_old = 99999999999999999L;
+#endif
 
     check_nursery_at_transaction_start();
 }
@@ -458,6 +470,7 @@
         }));
 
     list_clear(STM_PSEGMENT->modified_old_objects);
+    list_clear(STM_PSEGMENT->modified_old_objects_markers);
 }
 
 static void _finish_transaction(int attribute_to)
@@ -596,6 +609,7 @@
         }));
 
     list_clear(pseg->modified_old_objects);
+    list_clear(pseg->modified_old_objects_markers);
 }
 
 static void abort_data_structures_from_segment_num(int segment_num)
diff --git a/c7/stm/core.h b/c7/stm/core.h
--- a/c7/stm/core.h
+++ b/c7/stm/core.h
@@ -78,9 +78,17 @@
     /* List of old objects (older than the current transaction) that the
        current transaction attempts to modify.  This is used to track
        the STM status: they are old objects that where written to and
-       that need to be copied to other segments upon commit. */
+       that need to be copied to other segments upon commit.  Note that
+       every object takes three list items: the object, and two words for
+       the location marker. */
     struct list_s *modified_old_objects;
 
+    /* For each entry in 'modified_old_objects', we have two entries
+       in the following list, which give the marker at the time we added
+       the entry to modified_old_objects. */
+    struct list_s *modified_old_objects_markers;
+    uintptr_t modified_old_objects_markers_num_old;
+
     /* List of out-of-nursery objects that may contain pointers to
        nursery objects.  This is used to track the GC status: they are
        all objects outside the nursery on which an stm_write() occurred
diff --git a/c7/stm/gcpage.c b/c7/stm/gcpage.c
--- a/c7/stm/gcpage.c
+++ b/c7/stm/gcpage.c
@@ -418,6 +418,19 @@
     }
 }
 
+static void mark_visit_from_markers(void)
+{
+    long j;
+    for (j = 1; j <= NB_SEGMENTS; j++) {
+        char *base = get_segment_base(j);
+        struct list_s *lst = get_priv_segment(j)->modified_old_objects_markers;
+        uintptr_t i;
+        for (i = list_count(lst); i > 0; i -= 2) {
+            mark_visit_object((object_t *)list_item(lst, i - 1), base);
+        }
+    }
+}
+
 static void clean_up_segment_lists(void)
 {
     long i;
@@ -520,6 +533,7 @@
     /* marking */
     LIST_CREATE(mark_objects_to_trace);
     mark_visit_from_modified_objects();
+    mark_visit_from_markers();
     mark_visit_from_roots();
     LIST_FREE(mark_objects_to_trace);
 
diff --git a/c7/stm/list.h b/c7/stm/list.h
--- a/c7/stm/list.h
+++ b/c7/stm/list.h
@@ -33,6 +33,18 @@
 
 #define LIST_APPEND(lst, e)   ((lst) = list_append((lst), (uintptr_t)(e)))
 
+static inline struct list_s *list_append2(struct list_s *lst,
+                                          uintptr_t item0, uintptr_t item1)
+{
+    uintptr_t index = lst->count;
+    lst->count += 2;
+    if (UNLIKELY(index >= lst->last_allocated))
+        lst = _list_grow(lst, index + 1);
+    lst->items[index + 0] = item0;
+    lst->items[index + 1] = item1;
+    return lst;
+}
+
 
 static inline void list_clear(struct list_s *lst)
 {
@@ -66,6 +78,11 @@
     lst->items[index] = newitem;
 }
 
+static inline uintptr_t *list_ptr_to_item(struct list_s *lst, uintptr_t index)
+{
+    return &lst->items[index];
+}
+
 #define LIST_FOREACH_R(lst, TYPE, CODE)         \
     do {                                        \
         struct list_s *_lst = (lst);            \
diff --git a/c7/stm/marker.c b/c7/stm/marker.c
--- a/c7/stm/marker.c
+++ b/c7/stm/marker.c
@@ -11,38 +11,53 @@
                           const char *marker);
 
 
+static void marker_fetch(stm_thread_local_t *tl, uintptr_t marker[2])
+{
+    struct stm_shadowentry_s *current = tl->shadowstack - 1;
+    struct stm_shadowentry_s *base = tl->shadowstack_base;
+    /* stop walking just before shadowstack_base, which contains
+       STM_STACK_MARKER_OLD which shouldn't be expanded */
+    while (--current > base) {
+        if (((uintptr_t)current->ss) & 1) {
+            /* found the odd marker */
+            marker[0] = (uintptr_t)current[0].ss;
+            marker[1] = (uintptr_t)current[1].ss;
+            return;
+        }
+    }
+    marker[0] = 0;
+    marker[1] = 0;
+}
+
+static void marker_expand(uintptr_t marker[2], char *segment_base,
+                          char *outmarker)
+{
+    if (marker[0] == 0)
+        return;   /* no marker entry found */
+    if (outmarker[0] != 0)
+        return;   /* already collected an entry */
+    if (stmcb_expand_marker != NULL) {
+        stmcb_expand_marker(segment_base, marker[0], (object_t *)marker[1],
+                            outmarker, _STM_MARKER_LEN);
+    }
+}
+
 static void marker_fetch_expand(struct stm_priv_segment_info_s *pseg)
 {
-    if (pseg->marker_self[0] != 0)
-        return;   /* already collected an entry */
-
-    if (stmcb_expand_marker != NULL) {
-        stm_thread_local_t *tl = pseg->pub.running_thread;
-        struct stm_shadowentry_s *current = tl->shadowstack - 1;
-        struct stm_shadowentry_s *base = tl->shadowstack_base;
-        /* stop walking just before shadowstack_base, which contains
-           STM_STACK_MARKER_OLD which shouldn't be expanded */
-        while (--current > base) {
-            uintptr_t x = (uintptr_t)current->ss;
-            if (x & 1) {
-                /* the stack entry is an odd number */
-                stmcb_expand_marker(pseg->pub.segment_base, x, current[1].ss,
-                                    pseg->marker_self, _STM_MARKER_LEN);
-
-                if (pseg->marker_self[0] != 0)
-                    break;
-            }
-        }
-    }
+    uintptr_t marker[2];
+    marker_fetch(pseg->pub.running_thread, marker);
+    marker_expand(marker, pseg->pub.segment_base, pseg->marker_self);
 }
 
 char *_stm_expand_marker(void)
 {
-    struct stm_priv_segment_info_s *pseg =
-        get_priv_segment(STM_SEGMENT->segment_num);
-    pseg->marker_self[0] = 0;
-    marker_fetch_expand(pseg);
-    return pseg->marker_self;
+    /* for tests only! */
+    static char _result[_STM_MARKER_LEN];
+    uintptr_t marker[2];
+    _result[0] = 0;
+    marker_fetch(STM_SEGMENT->running_thread, marker);
+    marker_expand(marker, STM_SEGMENT->segment_base, _result);
+    return _result;
 }
 
 static void marker_copy(stm_thread_local_t *tl,
diff --git a/c7/stm/marker.h b/c7/stm/marker.h
--- a/c7/stm/marker.h
+++ b/c7/stm/marker.h
@@ -1,4 +1,7 @@
 
+static void marker_fetch(stm_thread_local_t *tl, uintptr_t marker[2]);
+static void marker_expand(uintptr_t marker[2], char *segment_base,
+                          char *outmarker);
 static void marker_fetch_expand(struct stm_priv_segment_info_s *pseg);
 static void marker_copy(stm_thread_local_t *tl,
                         struct stm_priv_segment_info_s *pseg,
diff --git a/c7/stm/nursery.c b/c7/stm/nursery.c
--- a/c7/stm/nursery.c
+++ b/c7/stm/nursery.c
@@ -232,6 +232,18 @@
                    _collect_now(item));
 }
 
+static void collect_roots_from_markers(uintptr_t num_old)
+{
+    /* visit the marker objects */
+    struct list_s *mlst = STM_PSEGMENT->modified_old_objects_markers;
+    STM_PSEGMENT->modified_old_objects_markers_num_old = list_count(mlst);
+    uintptr_t i, total = list_count(mlst);
+    assert((total & 1) == 0);
+    for (i = num_old + 1; i < total; i += 2) {
+        minor_trace_if_young((object_t **)list_ptr_to_item(mlst, i));
+    }
+}
+
 static size_t throw_away_nursery(struct stm_priv_segment_info_s *pseg)
 {
     /* reset the nursery by zeroing it */
@@ -296,6 +308,7 @@
     /* All the objects we move out of the nursery become "overflow"
        objects.  We use the list 'objects_pointing_to_nursery'
        to hold the ones we didn't trace so far. */
+    uintptr_t num_old;
     if (STM_PSEGMENT->objects_pointing_to_nursery == NULL) {
         STM_PSEGMENT->objects_pointing_to_nursery = list_create();
 
@@ -305,7 +318,12 @@
            into objects_pointing_to_nursery, but instead we use the
            following shortcut */
         collect_modified_old_objects();
+        num_old = 0;
     }
+    else
+        num_old = STM_PSEGMENT->modified_old_objects_markers_num_old;
+
+    collect_roots_from_markers(num_old);
 
     collect_roots_in_nursery();
 
diff --git a/c7/stm/setup.c b/c7/stm/setup.c
--- a/c7/stm/setup.c
+++ b/c7/stm/setup.c
@@ -78,6 +78,7 @@
         pr->objects_pointing_to_nursery = NULL;
         pr->large_overflow_objects = NULL;
         pr->modified_old_objects = list_create();
+        pr->modified_old_objects_markers = list_create();
         pr->young_weakrefs = list_create();
         pr->old_weakrefs = list_create();
         pr->young_outside_nursery = tree_create();
@@ -115,6 +116,7 @@
         assert(pr->objects_pointing_to_nursery == NULL);
         assert(pr->large_overflow_objects == NULL);
         list_free(pr->modified_old_objects);
+        list_free(pr->modified_old_objects_markers);
         list_free(pr->young_weakrefs);
         list_free(pr->old_weakrefs);
         tree_free(pr->young_outside_nursery);
diff --git a/c7/test/test_marker.py b/c7/test/test_marker.py
--- a/c7/test/test_marker.py
+++ b/c7/test/test_marker.py
@@ -159,8 +159,6 @@
         @ffi.callback("void(char *, uintptr_t, object_t *, char *, size_t)")
         def expand_marker(base, number, ptr, outbuf, outbufsize):
             seen.append(number)
-            if ptr == ffi.NULL:
-                return
             s = '%d %r\x00' % (number, ptr)
             assert len(s) <= outbufsize
             outbuf[0:len(s)] = s
@@ -174,8 +172,8 @@
         self.push_root(ffi.cast("object_t *", 29))
         self.push_root(ffi.cast("object_t *", ffi.NULL))
         raw = lib._stm_expand_marker()
-        assert ffi.string(raw) == '27 %r' % (p,)
-        assert seen == [29, 27]
+        assert ffi.string(raw).startswith('29 ')
+        assert seen == [29]
 
     def test_double_abort_markers_cb(self):
         @ffi.callback("void(char *, uintptr_t, object_t *, char *, size_t)")
@@ -190,6 +188,10 @@
         self.push_root(ffi.cast("object_t *", 19))
         self.push_root(ffi.cast("object_t *", ffi.NULL))
         stm_set_char(p, 'A')
+        self.pop_root()
+        self.pop_root()
+        self.push_root(ffi.cast("object_t *", 17))
+        self.push_root(ffi.cast("object_t *", ffi.NULL))
         #
         self.switch(1)
         self.start_transaction()
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to