[pypy-commit] stmgc card-marking: fixes

Raemi noreply at buildbot.pypy.org
Tue May 20 14:29:49 CEST 2014


Author: Remi Meier <remi.meier at inf.ethz.ch>
Branch: card-marking
Changeset: r1219:a290c9b39ef9
Date: 2014-05-20 14:30 +0200
http://bitbucket.org/pypy/stmgc/changeset/a290c9b39ef9/

Log:	fixes

diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -42,6 +42,9 @@
 
 static void _stm_mark_card(object_t *obj, uintptr_t card_index)
 {
+    assert(card_index > 0);
+    dprintf(("mark %p card %lu\n", obj, card_index));
+
     if (!(obj->stm_flags & GCFLAG_CARDS_SET)) {
         /* not yet in the list */
         if (STM_PSEGMENT->old_objects_with_cards) {
@@ -56,8 +59,11 @@
        to know what may have changed.
        We already own the object here or it is an overflow obj. */
     uintptr_t card_lock_idx = get_write_lock_idx((uintptr_t)obj) + card_index;
+
     assert(write_locks[card_lock_idx] == 0
            || write_locks[card_lock_idx] == STM_PSEGMENT->write_lock_num);
+    assert(get_write_lock_idx((uintptr_t)obj) != card_lock_idx);
+
     if (!write_locks[card_lock_idx])
         write_locks[card_lock_idx] = STM_PSEGMENT->write_lock_num;
 }
@@ -175,7 +181,8 @@
         }
     }
     else if (write_locks[base_lock_idx] == lock_num) {
-        OPT_ASSERT(STM_PSEGMENT->objects_pointing_to_nursery != NULL);
+        assert(IMPLY(!(obj->stm_flags & GCFLAG_CARDS_SET),
+                     STM_PSEGMENT->objects_pointing_to_nursery != NULL));
 #ifdef STM_TESTS
         bool found = false;
         LIST_FOREACH_R(STM_PSEGMENT->modified_old_objects, object_t *,
diff --git a/c7/stm/misc.c b/c7/stm/misc.c
--- a/c7/stm/misc.c
+++ b/c7/stm/misc.c
@@ -67,6 +67,13 @@
     return list_count(STM_PSEGMENT->objects_pointing_to_nursery);
 }
 
+long _stm_count_old_objects_with_cards(void)
+{
+    if (STM_PSEGMENT->old_objects_with_cards == NULL)
+        return -1;
+    return list_count(STM_PSEGMENT->old_objects_with_cards);
+}
+
 object_t *_stm_enum_modified_old_objects(long index)
 {
     return (object_t *)list_item(
@@ -79,6 +86,12 @@
         STM_PSEGMENT->objects_pointing_to_nursery, index);
 }
 
+object_t *_stm_enum_old_objects_with_cards(long index)
+{
+    return (object_t *)list_item(
+        STM_PSEGMENT->old_objects_with_cards, index);
+}
+
 uint64_t _stm_total_allocated(void)
 {
     return increment_total_allocated(0);
diff --git a/c7/stm/nursery.c b/c7/stm/nursery.c
--- a/c7/stm/nursery.c
+++ b/c7/stm/nursery.c
@@ -183,6 +183,23 @@
     minor_trace_if_young(&tl->thread_local_obj);
 }
 
+static void _reset_cards(object_t *obj)
+{
+    char *realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
+    size_t size = stmcb_size_rounded_up((struct object_s *)realobj);
+
+    uintptr_t first_card_index = get_write_lock_idx((uintptr_t)obj);
+    uintptr_t card_index = 1;
+    uintptr_t last_card_index = get_card_index(size - 1);
+    OPT_ASSERT(last_card_index >= card_index);
+    while (card_index <= last_card_index) {
+        write_locks[first_card_index + card_index] = 0;
+        card_index++;
+    }
+
+    obj->stm_flags &= ~GCFLAG_CARDS_SET;
+}
+
 static __thread object_t *_card_base_obj;
 static void minor_trace_if_young_cards(object_t **pobj)
 {
@@ -205,37 +222,51 @@
     /* XXX HACK XXX: */
     _card_base_obj = obj;
     assert(!_is_in_nursery(obj));
+    assert(obj->stm_flags & GCFLAG_CARDS_SET);
+
+    dprintf(("_trace_card_object(%p)\n", obj));
+
     char *realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
     stmcb_trace((struct object_s *)realobj, &minor_trace_if_young_cards);
+
+    _reset_cards(obj);
 }
 
+
+
 static inline void _collect_now(object_t *obj)
 {
     assert(!_is_young(obj));
 
     dprintf(("_collect_now: %p\n", obj));
-    assert(IMPLY(obj->stm_flags & GCFLAG_WRITE_BARRIER,
-                 obj->stm_flags & GCFLAG_CARDS_SET));
+
     if (!(obj->stm_flags & GCFLAG_WRITE_BARRIER)) {
-        /* do normal full trace, even if also card-marked */
-        obj->stm_flags |= GCFLAG_WRITE_BARRIER;
-        dprintf(("-> has no cards\n"));
         /* 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);
-    } else {
-        /* only trace cards */
-        dprintf(("-> has cards\n"));
+
+        obj->stm_flags |= GCFLAG_WRITE_BARRIER;
+        if (obj->stm_flags & GCFLAG_CARDS_SET) {
+            _reset_cards(obj);
+        }
+    } if (obj->stm_flags & GCFLAG_CARDS_SET) {
         _trace_card_object(obj);
     }
+}
 
-    /* clear the CARDS_SET, but not the real cards since they are
-       still needed by STM conflict detection
-       XXX: maybe separate them since we now have to also trace all
-       these cards again in the next minor_collection */
-    obj->stm_flags &= ~GCFLAG_CARDS_SET;
+
+static void collect_cardrefs_to_nursery(void)
+{
+    struct list_s *lst = STM_PSEGMENT->old_objects_with_cards;
+
+    while (!list_is_empty(lst)) {
+        object_t *obj = (object_t*)list_pop_item(lst);
+
+        assert(obj->stm_flags & GCFLAG_CARDS_SET);
+        _collect_now(obj);
+    }
 }
 
 static void collect_oldrefs_to_nursery(void)
@@ -270,8 +301,9 @@
 
 static void collect_modified_old_objects(void)
 {
-    LIST_FOREACH_R(STM_PSEGMENT->modified_old_objects, object_t * /*item*/,
-                   _collect_now(item));
+    LIST_FOREACH_R(
+        STM_PSEGMENT->modified_old_objects, object_t * /*item*/,
+        _collect_now(item));
 }
 
 static void collect_roots_from_markers(uintptr_t num_old)
@@ -371,6 +403,7 @@
        to hold the ones we didn't trace so far. */
     uintptr_t num_old;
     if (STM_PSEGMENT->objects_pointing_to_nursery == NULL) {
+        assert(STM_PSEGMENT->old_objects_with_cards == NULL);
         STM_PSEGMENT->objects_pointing_to_nursery = list_create();
         STM_PSEGMENT->old_objects_with_cards = list_create();
 
@@ -390,7 +423,9 @@
 
     collect_roots_in_nursery();
 
+    collect_cardrefs_to_nursery();
     collect_oldrefs_to_nursery();
+    assert(list_is_empty(STM_PSEGMENT->old_objects_with_cards));
 
     /* now all surviving nursery objects have been moved out */
     stm_move_young_weakrefs();
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -138,8 +138,10 @@
 void _stm_set_nursery_free_count(uint64_t free_count);
 long _stm_count_modified_old_objects(void);
 long _stm_count_objects_pointing_to_nursery(void);
+long _stm_count_old_objects_with_cards(void);
 object_t *_stm_enum_modified_old_objects(long index);
 object_t *_stm_enum_objects_pointing_to_nursery(long index);
+object_t *_stm_enum_old_objects_with_cards(long index);
 uint64_t _stm_total_allocated(void);
 #endif
 
diff --git a/c7/test/support.py b/c7/test/support.py
--- a/c7/test/support.py
+++ b/c7/test/support.py
@@ -101,8 +101,11 @@
 
 long _stm_count_modified_old_objects(void);
 long _stm_count_objects_pointing_to_nursery(void);
+long _stm_count_old_objects_with_cards(void);
 object_t *_stm_enum_modified_old_objects(long index);
 object_t *_stm_enum_objects_pointing_to_nursery(long index);
+object_t *_stm_enum_old_objects_with_cards(long index);
+
 
 void stm_collect(long level);
 uint64_t _stm_total_allocated(void);
@@ -496,6 +499,14 @@
         return None
     return map(lib._stm_enum_objects_pointing_to_nursery, range(count))
 
+def old_objects_with_cards():
+    count = lib._stm_count_old_objects_with_cards()
+    if count < 0:
+        return None
+    return map(lib._stm_enum_old_objects_with_cards, range(count))
+
+
+
 
 SHADOWSTACK_LENGTH = 1000
 _keepalive = weakref.WeakKeyDictionary()
diff --git a/c7/test/test_card_marking.py b/c7/test/test_card_marking.py
--- a/c7/test/test_card_marking.py
+++ b/c7/test/test_card_marking.py
@@ -54,3 +54,66 @@
         dn = stm_get_ref(o, 0)
         assert is_in_nursery(dn)
         assert dn == d
+
+        assert not stm_was_written(o)
+        stm_write_card(o, 2)
+        assert stm_was_written_card(o)
+
+        # card cleared after last collection,
+        # so no retrace of index 199:
+        d2 = stm_allocate(64, True)
+        # without a write-barrier:
+        lib._set_ptr(o, 199, d2)
+        self.push_root(o)
+        stm_minor_collect()
+        o = self.pop_root()
+        # d2 was not traced!
+        dn = stm_get_ref(o, 199)
+        assert is_in_nursery(dn)
+        assert dn == d2
+
+    def test_nursery2(self):
+        o = stm_allocate_old_refs(200, True)
+        self.start_transaction()
+        p = stm_allocate(64)
+        d = stm_allocate(64)
+        e = stm_allocate(64)
+        stm_set_ref(o, 199, p, True)
+        stm_set_ref(o, 1, d, False)
+        lib._set_ptr(o, 100, e)
+
+        self.push_root(o)
+        stm_minor_collect()
+        o = self.pop_root()
+
+        # stm_write in stm_set_ref made it trace everything
+        assert not is_in_nursery(stm_get_ref(o, 199))
+        assert not is_in_nursery(stm_get_ref(o, 1))
+        assert not is_in_nursery(stm_get_ref(o, 100))
+
+    def test_nursery3(self):
+        o = stm_allocate_old_refs(200, True)
+        self.start_transaction()
+        stm_minor_collect()
+
+        p = stm_allocate(64)
+        d = stm_allocate(64)
+        e = stm_allocate(64)
+        stm_set_ref(o, 199, p, True)
+        stm_set_ref(o, 1, d, True)
+        lib._set_ptr(o, 100, e) # no card marked!
+
+        assert not stm_was_written(o)
+        assert stm_was_written_card(o)
+
+        print modified_old_objects()
+        print objects_pointing_to_nursery()
+        print old_objects_with_cards()
+
+        self.push_root(o)
+        stm_minor_collect()
+        o = self.pop_root()
+
+        assert not is_in_nursery(stm_get_ref(o, 199))
+        assert not is_in_nursery(stm_get_ref(o, 1))
+        assert stm_get_ref(o, 100) == e # not traced


More information about the pypy-commit mailing list