[pypy-commit] stmgc c7-refactor: Fixes.

arigo noreply at buildbot.pypy.org
Tue Feb 25 00:45:22 CET 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: c7-refactor
Changeset: r848:c2dc9f28006f
Date: 2014-02-25 00:45 +0100
http://bitbucket.org/pypy/stmgc/changeset/c2dc9f28006f/

Log:	Fixes.

diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -104,6 +104,15 @@
        getting the write-lock */
     assert(obj->stm_flags & GCFLAG_WRITE_BARRIER);
     obj->stm_flags &= ~GCFLAG_WRITE_BARRIER;
+
+    /* for sanity, check that all other segment copies of this object
+       still have the flag */
+    long i;
+    for (i = 0; i < NB_SEGMENTS; i++) {
+        assert(i == STM_SEGMENT->segment_num ||
+               (((struct object_s *)REAL_ADDRESS(get_segment_base(i), obj))
+                ->stm_flags & GCFLAG_WRITE_BARRIER));
+    }
 }
 
 static void reset_transaction_read_version(void)
@@ -292,9 +301,9 @@
             assert(write_locks[lock_idx] == STM_PSEGMENT->write_lock_num);
             write_locks[lock_idx] = 0;
 
-            /* set again the WRITE_BARRIER flag */
-            assert((item->stm_flags & GCFLAG_WRITE_BARRIER) == 0);
-            item->stm_flags |= GCFLAG_WRITE_BARRIER;
+            /* the WRITE_BARRIER flag should have been set again by
+               minor_collection() */
+            assert((item->stm_flags & GCFLAG_WRITE_BARRIER) != 0);
 
             /* copy the modified object to the other segment */
             char *src = REAL_ADDRESS(local_base, item);
@@ -363,6 +372,7 @@
     /* update 'overflow_number' if needed */
     if (has_any_overflow_object) {
         highest_overflow_number += GCFLAG_OVERFLOW_NUMBER_bit0;
+        assert(highest_overflow_number != 0);   /* XXX else, overflow! */
         STM_PSEGMENT->overflow_number = highest_overflow_number;
     }
 
@@ -393,9 +403,6 @@
         STM_PSEGMENT->modified_old_objects,
         object_t * /*item*/,
         ({
-            /* all objects in 'modified_objects' have this flag removed */
-            assert((item->stm_flags & GCFLAG_WRITE_BARRIER) == 0);
-
             /* memcpy in the opposite direction than
                push_modified_to_other_segments() */
             char *src = REAL_ADDRESS(remote_base, item);
@@ -403,8 +410,10 @@
             ssize_t size = stmcb_size_rounded_up((struct object_s *)src);
             memcpy(dst, src, size);
 
-            /* copying from the other segment added again the
-               WRITE_BARRIER flag */
+            /* objects in 'modified_old_objects' usually have the
+               WRITE_BARRIER flag, unless they have been modified
+               recently.  Ignore the old flag; after copying from the
+               other segment, we should have the flag. */
             assert(item->stm_flags & GCFLAG_WRITE_BARRIER);
 
             /* write all changes to the object before we release the
diff --git a/c7/stm/core.h b/c7/stm/core.h
--- a/c7/stm/core.h
+++ b/c7/stm/core.h
@@ -68,13 +68,13 @@
     struct list_s *modified_old_objects;
 
     /* 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 since the last minor collection.  If there was no
-       minor collection yet in the current transaction, this is NULL,
+       nursery objects.  This is used to track the GC status: they are
+       all objects outside the nursery on which an stm_write() occurred
+       since the last minor collection.  This list contains exactly the
+       objects without GCFLAG_WRITE_BARRIER.  If there was no minor
+       collection yet in the current transaction, this is NULL,
        understood as meaning implicitly "this is the same as
-       'modified_old_objects'.  This list contains exactly the
-       objects without GCFLAG_WRITE_BARRIER. */
+       'modified_old_objects'". */
     struct list_s *objects_pointing_to_nursery;
 
     /* List of all large, overflowed objects.  Only non-NULL after the
diff --git a/c7/stm/nursery.c b/c7/stm/nursery.c
--- a/c7/stm/nursery.c
+++ b/c7/stm/nursery.c
@@ -51,6 +51,7 @@
 /************************************************************/
 
 #define GCWORD_MOVED  ((object_t *) -42)
+#define FLAG_SYNC_LARGE_NOW   0x01
 
 
 static void minor_trace_if_young(object_t **pobj)
@@ -80,19 +81,21 @@
     char *realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
     size_t size = stmcb_size_rounded_up((struct object_s *)realobj);
     object_t *nobj;
+    uintptr_t nobj_sync_now;
 
     if (1 /*size >= GC_MEDIUM_REQUEST*/) {
 
         /* case 1: object is not small enough.
            Ask gcpage.c for an allocation via largemalloc. */
         nobj = allocate_outside_nursery_large(size);
+        nobj_sync_now = (uintptr_t)nobj;
 
         /* Copy the object  */
         char *realnobj = REAL_ADDRESS(STM_SEGMENT->segment_base, nobj);
         memcpy(realnobj, realobj, size);
 
         if (STM_PSEGMENT->minor_collect_will_commit_now)
-            synchronize_overflow_object_now(nobj);
+            nobj_sync_now |= FLAG_SYNC_LARGE_NOW;
         else
             LIST_APPEND(STM_PSEGMENT->large_overflow_objects, nobj);
     }
@@ -107,13 +110,13 @@
     }
 
     /* Done copying the object. */
-    //dprintf(("%p -> %p\n", obj, nobj));
+    //dprintf(("\t\t\t\t\t%p -> %p\n", obj, nobj));
     pforwarded_array[0] = GCWORD_MOVED;
     pforwarded_array[1] = nobj;
     *pobj = nobj;
 
     /* Must trace the object later */
-    LIST_APPEND(STM_PSEGMENT->objects_pointing_to_nursery, nobj);
+    LIST_APPEND(STM_PSEGMENT->objects_pointing_to_nursery, nobj_sync_now);
 }
 
 static void collect_roots_in_nursery(void)
@@ -127,26 +130,46 @@
     }
 }
 
+static inline void _collect_now(object_t *obj)
+{
+    assert(!_is_in_nursery(obj));
+
+    /* We must not have GCFLAG_WRITE_BARRIER so far.  Add it now. */
+    assert(!(obj->stm_flags & GCFLAG_WRITE_BARRIER));
+    obj->stm_flags |= GCFLAG_WRITE_BARRIER;
+
+    /* Trace the 'obj' to replace pointers to nursery with pointers
+       outside the nursery, possibly forcing nursery objects out and
+       adding them to 'objects_pointing_to_nursery' as well. */
+    char *realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
+    stmcb_trace((struct object_s *)realobj, &minor_trace_if_young);
+}
+
 static void collect_oldrefs_to_nursery(void)
 {
     struct list_s *lst = STM_PSEGMENT->objects_pointing_to_nursery;
 
     while (!list_is_empty(lst)) {
-        object_t *obj = (object_t *)list_pop_item(lst);
-        assert(!_is_in_nursery(obj));
+        uintptr_t obj_sync_now = list_pop_item(lst);
+        object_t *obj = (object_t *)(obj_sync_now & ~FLAG_SYNC_LARGE_NOW);
 
-        /* We must not have GCFLAG_WRITE_BARRIER so far.  Add it now. */
-        assert(!(obj->stm_flags & GCFLAG_WRITE_BARRIER));
-        obj->stm_flags |= GCFLAG_WRITE_BARRIER;
+        _collect_now(obj);
 
-        /* Trace the 'obj' to replace pointers to nursery with pointers
-           outside the nursery, possibly forcing nursery objects out and
-           adding them to 'objects_pointing_to_nursery' as well. */
-        char *realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
-        stmcb_trace((struct object_s *)realobj, &minor_trace_if_young);
+        if (obj_sync_now & FLAG_SYNC_LARGE_NOW) {
+            /* synchronize the object to other segments *now* -- which
+               means, just after we added the WRITE_BARRIER flag and
+               traced into it, because tracing might change it again. */
+            synchronize_overflow_object_now(obj);
+        }
     }
 }
 
+static void collect_modified_old_objects(void)
+{
+    LIST_FOREACH_R(STM_PSEGMENT->modified_old_objects, object_t * /*item*/,
+                   _collect_now(item));
+}
+
 static void throw_away_nursery(void)
 {
     /* reset the nursery by zeroing it */
@@ -181,17 +204,25 @@
 
     STM_PSEGMENT->minor_collect_will_commit_now = commit;
 
-    /* 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. */
-    if (STM_PSEGMENT->objects_pointing_to_nursery == NULL)
-        STM_PSEGMENT->objects_pointing_to_nursery = list_create();
-
     /* We need this to track the large overflow objects for a future
        commit.  We don't need it if we're committing now. */
     if (!commit && STM_PSEGMENT->large_overflow_objects == NULL)
         STM_PSEGMENT->large_overflow_objects = list_create();
 
+    /* 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. */
+    if (STM_PSEGMENT->objects_pointing_to_nursery == NULL) {
+        STM_PSEGMENT->objects_pointing_to_nursery = list_create();
+
+        /* See the doc of 'objects_pointing_to_nursery': if it is NULL,
+           then it is implicitly understood to be equal to
+           'modified_old_objects'.  We could copy modified_old_objects
+           into objects_pointing_to_nursery, but instead we use the
+           following shortcut */
+        collect_modified_old_objects();
+    }
+
     collect_roots_in_nursery();
 
     collect_oldrefs_to_nursery();
diff --git a/c7/test/test_random.py b/c7/test/test_random.py
--- a/c7/test/test_random.py
+++ b/c7/test/test_random.py
@@ -164,6 +164,7 @@
     def pop_roots(self, ex):
         for r in reversed(self.saved_roots[self.roots_on_transaction_start:]):
             ex.do('%s = self.pop_root()' % r)
+            ex.do('# 0x%x' % (int(ffi.cast("uintptr_t", ex.content[r])),))
             self.roots_on_stack -= 1
         assert self.roots_on_stack == self.roots_on_transaction_start
 
@@ -175,7 +176,8 @@
             for r in reversed(to_reload):
                 ex.do('%s = self.pop_root()' % r)
             for r in to_reload:
-                ex.do('self.push_root(%s)' % r)
+                ex.do('self.push_root(%s)  # 0x%x' % (
+                    r, int(ffi.cast("uintptr_t", ex.content[r]))))
 
     def start_transaction(self):
         assert self.transaction_state is None


More information about the pypy-commit mailing list