Author: Remi Meier <[email protected]>
Branch: card-marking
Changeset: r1243:ea910eddec2e
Date: 2014-05-23 12:04 +0200
http://bitbucket.org/pypy/stmgc/changeset/ea910eddec2e/

Log:    possible change in API (closer to pypy, but needs more nasty
        callbacks)

diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -40,9 +40,10 @@
 #endif
 }
 
-void _stm_mark_card(object_t *obj, uintptr_t card_index)
+__attribute__((always_inline))
+void _stm_mark_card(object_t *obj, uintptr_t index)
 {
-    assert(card_index > 0);
+    assert(index != -1);
 
     assert(obj->stm_flags & GCFLAG_HAS_CARDS);
     assert(!(obj->stm_flags & GCFLAG_SMALL_UNIFORM)); /* not supported/tested 
*/
@@ -54,8 +55,6 @@
     /* we need at least one lock in addition to the STM-reserved object 
write-lock */
 #endif
 
-    dprintf(("mark %p card %lu with %d\n", obj, card_index, CARD_MARKED));
-
     if (!(obj->stm_flags & GCFLAG_CARDS_SET)) {
         /* not yet in the list */
         if (STM_PSEGMENT->old_objects_with_cards) {
@@ -69,24 +68,27 @@
     /* Just acquire the corresponding lock for the next minor_collection
        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;
+    uintptr_t card_lock_idx = get_write_lock_idx((uintptr_t)obj);
+    card_lock_idx += get_index_to_card_index(index);
 
     assert(write_locks[get_write_lock_idx((uintptr_t)obj)] == 0 /* overflow 
obj */
            || write_locks[get_write_lock_idx((uintptr_t)obj)] == 
STM_PSEGMENT->write_lock_num);
     assert(get_write_lock_idx((uintptr_t)obj) != card_lock_idx);
 
+    dprintf(("mark %p index %lu, card:%lu with %d\n",
+             obj, index, get_index_to_card_index(index), CARD_MARKED));
     if (write_locks[card_lock_idx] != CARD_MARKED)
         write_locks[card_lock_idx] = CARD_MARKED;
 }
 
-static bool _stm_write_slowpath_overflow_objs(object_t *obj, uintptr_t 
card_index)
+static bool _stm_write_slowpath_overflow_objs(object_t *obj, uintptr_t index)
 {
     /* is this an object from the same transaction, outside the nursery? */
     if (IS_OVERFLOW_OBJ(STM_PSEGMENT, obj)) {
         assert(STM_PSEGMENT->objects_pointing_to_nursery != NULL);
-        dprintf_test(("write_slowpath %p -> ovf obj_to_nurs\n", obj));
+        dprintf_test(("write_slowpath %p -> ovf obj_to_nurs, index:%lu\n", 
obj, index));
 
-        if (!card_index) {
+        if (index == -1) {
             /* no card to be marked, don't call again until next collection */
             obj->stm_flags &= ~GCFLAG_WRITE_BARRIER;
             LIST_APPEND(STM_PSEGMENT->objects_pointing_to_nursery, obj);
@@ -94,7 +96,7 @@
             /* don't remove GCFLAG_WRITE_BARRIER because we need to be
                here for every card to mark */
             assert(STM_PSEGMENT->old_objects_with_cards);
-            _stm_mark_card(obj, card_index);
+            _stm_mark_card(obj, index);
         }
 
         /* We don't need to do anything in the STM part of the WB slowpath: */
@@ -107,26 +109,29 @@
 
 void _stm_write_slowpath(object_t *obj)
 {
-    _stm_write_slowpath_card(obj, 0);
+    _stm_write_slowpath_card(obj, -1);
 }
 
-void _stm_write_slowpath_card(object_t *obj, uintptr_t card_index)
+void _stm_write_slowpath_card(object_t *obj, uintptr_t index)
 {
     assert(_seems_to_be_running_transaction());
     assert(!_is_young(obj));
     assert(obj->stm_flags & GCFLAG_WRITE_BARRIER);
-    assert(IMPLY(card_index, (card_index - 1) * CARD_SIZE < 
stmcb_size_rounded_up(
-                     (struct object_s*)REAL_ADDRESS(STM_SEGMENT->segment_base, 
obj))));
+    assert(IMPLY(index != -1, index < stmcb_size_rounded_up(
+                 (struct object_s*)REAL_ADDRESS(STM_SEGMENT->segment_base, 
obj))));
 
     uintptr_t base_lock_idx = get_write_lock_idx((uintptr_t)obj);
     uint8_t lock_num = STM_PSEGMENT->write_lock_num;
+    bool mark_cards = index != -1;
+
     assert(base_lock_idx < sizeof(write_locks));
+    if (!(obj->stm_flags & GCFLAG_HAS_CARDS)) {
+        index = -1;
+        mark_cards = false;         /* assume no cards */
+    }
 
-    if (!(obj->stm_flags & GCFLAG_HAS_CARDS))
-        card_index = 0;         /* assume no cards */
-
-    /* if card_index and obj->stm_flags & CARDS_SET:
-           directly mark the card of obj at card_index
+    /* if mark_cards and obj->stm_flags & CARDS_SET:
+           directly mark the card of obj at index
            return (no STM part needed)
        -> see stmgc.h */
     /* if CARDS_SET, we entered here at least once, so we own the write_lock
@@ -137,7 +142,7 @@
               || (IS_OVERFLOW_OBJ(STM_PSEGMENT, obj) && 
write_locks[base_lock_idx] == 0)
               ));
 
-    if (_stm_write_slowpath_overflow_objs(obj, card_index))
+    if (_stm_write_slowpath_overflow_objs(obj, index))
         return;
 
     /* do a read-barrier now.  Note that this must occur before the
@@ -233,7 +238,7 @@
 
     /* A common case for write_locks[] that was either 0 or lock_num:
        we need to add the object to the appropriate list if there is one. */
-    if (!card_index) {
+    if (!mark_cards) {
         if (STM_PSEGMENT->objects_pointing_to_nursery != NULL) {
             dprintf_test(("write_slowpath %p -> old obj_to_nurs\n", obj));
             LIST_APPEND(STM_PSEGMENT->objects_pointing_to_nursery, obj);
@@ -246,7 +251,7 @@
 
     } else {
         /* don't remove WRITE_BARRIER */
-        _stm_mark_card(obj, card_index);
+        _stm_mark_card(obj, index);
     }
 
     /* for sanity, check again that all other segment copies of this
@@ -532,7 +537,7 @@
 
     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(obj_size - 1);
+    uintptr_t last_card_index = get_index_to_card_index(obj_size - 1); /* max 
valid index */
     long i, myself = STM_SEGMENT->segment_num;
 
     /* simple heuristic to check if probably the whole object is
@@ -554,10 +559,8 @@
        try yet to use page_copy() or otherwise take into account privatization
        of pages (except _has_private_page_in_range) */
     uintptr_t start = 0;
-    uintptr_t copy_size = 0;
     while (card_index <= last_card_index) {
         uintptr_t card_lock_idx = first_card_index + card_index;
-        uintptr_t card_byte_offset = get_card_byte_offset(card_index);
         uint8_t card_value = write_locks[card_lock_idx];
 
         OPT_ASSERT(card_value != CARD_MARKED); /* always only MARKED_OLD or 
CLEAR */
@@ -566,14 +569,8 @@
             write_locks[card_lock_idx] = CARD_CLEAR;
 
             if (start == 0) {   /* first marked card */
-                start = (uintptr_t)obj + card_byte_offset;
-            }
-
-            copy_size += CARD_SIZE;
-
-            if ((start - (uintptr_t)obj) + copy_size > obj_size) {
-                /* don't copy over the object's bounds */
-                copy_size = obj_size - (start - (uintptr_t)obj);
+                start = (uintptr_t)obj + stmcb_index_to_byte_offset(
+                    realobj, get_card_index_to_index(card_index));
             }
         }
 
@@ -581,7 +578,17 @@
             && (card_value != CARD_MARKED_OLD         /* found non-marked card 
*/
                 || card_index == last_card_index)) {  /* this is the last card 
*/
             /* do the copying: */
-            //dprintf(("copy %lu bytes\n", copy_size));
+            uintptr_t copy_size;
+
+            uintptr_t next_card_offset = stmcb_index_to_byte_offset(
+                realobj, get_card_index_to_index(card_index + 1));
+
+            if (next_card_offset > obj_size)
+                next_card_offset = obj_size;
+
+            copy_size = next_card_offset - (start - (uintptr_t)obj);
+
+            /* dprintf(("copy %lu bytes\n", copy_size)); */
 
             /* since we have marked cards, at least one page here must be 
private */
             assert(_has_private_page_in_range(myself, start, copy_size));
diff --git a/c7/stm/core.h b/c7/stm/core.h
--- a/c7/stm/core.h
+++ b/c7/stm/core.h
@@ -236,11 +236,11 @@
 #define IS_OVERFLOW_OBJ(pseg, obj) (((obj)->stm_flags & 
-GCFLAG_OVERFLOW_NUMBER_bit0) \
                                     == (pseg)->overflow_number)
 
-static inline uintptr_t get_card_index(uintptr_t byte_offset) {
-    return (byte_offset / CARD_SIZE) + 1;
+static inline uintptr_t get_index_to_card_index(uintptr_t index) {
+    return (index / CARD_SIZE) + 1;
 }
 
-static inline uintptr_t get_card_byte_offset(uintptr_t card_index) {
+static inline uintptr_t get_card_index_to_index(uintptr_t card_index) {
     return (card_index - 1) * CARD_SIZE;
 }
 
diff --git a/c7/stm/nursery.c b/c7/stm/nursery.c
--- a/c7/stm/nursery.c
+++ b/c7/stm/nursery.c
@@ -197,7 +197,7 @@
 
     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);
+    uintptr_t last_card_index = get_index_to_card_index(size - 1); /* max 
valid index */
 
     OPT_ASSERT(write_locks[first_card_index] <= NB_SEGMENTS_MAX
                || write_locks[first_card_index] == 255); /* see gcpage.c */
@@ -256,7 +256,7 @@
 
     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);
+    uintptr_t last_card_index = get_index_to_card_index(size - 1); /* max 
valid index */
 
     OPT_ASSERT(write_locks[first_card_index] <= NB_SEGMENTS
                || write_locks[first_card_index] == 255); /* see gcpage.c */
@@ -281,39 +281,51 @@
 #pragma pop_macro("STM_PSEGMENT")
 }
 
-static __thread object_t *_card_base_obj;
-static void minor_trace_if_young_cards(object_t **pobj)
-{
-    /* XXX: add a specialised stmcb_trace_cards() that
-       also gives the obj-base */
-    assert(_card_base_obj);
-    uintptr_t base_lock_idx = get_write_lock_idx((uintptr_t)_card_base_obj);
-    uintptr_t card_lock_idx = base_lock_idx + get_card_index(
-        (uintptr_t)((char*)pobj - STM_SEGMENT->segment_base) - 
(uintptr_t)_card_base_obj);
-
-    if (write_locks[card_lock_idx] == CARD_MARKED) {
-        dprintf(("minor_trace_if_young_cards: trace %p\n", *pobj));
-        minor_trace_if_young(pobj);
-    }
-}
 
 static void _trace_card_object(object_t *obj)
 {
-    /* XXX HACK XXX: */
-    _card_base_obj = obj;
     assert(!_is_in_nursery(obj));
     assert(obj->stm_flags & GCFLAG_CARDS_SET);
     assert(obj->stm_flags & GCFLAG_WRITE_BARRIER);
 
     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);
-
     bool obj_is_overflow = IS_OVERFLOW_OBJ(STM_PSEGMENT, obj);
     uint8_t mark_value = obj_is_overflow ? CARD_CLEAR : CARD_MARKED_OLD;
-    _reset_object_cards(get_priv_segment(STM_SEGMENT->segment_num),
-                        obj, mark_value, false); /* mark marked */
+
+    struct object_s *realobj = (struct object_s 
*)REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
+    size_t size = stmcb_size_rounded_up(realobj);
+
+    uintptr_t first_card_index = get_write_lock_idx((uintptr_t)obj);
+    uintptr_t card_index = 1;
+    uintptr_t last_card_index = get_index_to_card_index(size - 1); /* max 
valid index */
+
+    OPT_ASSERT(write_locks[first_card_index] <= NB_SEGMENTS_MAX
+               || write_locks[first_card_index] == 255); /* see gcpage.c */
+
+    /* XXX: merge ranges */
+    while (card_index <= last_card_index) {
+        uintptr_t card_lock_idx = first_card_index + card_index;
+        if (write_locks[card_lock_idx] == CARD_MARKED) {
+            /* clear or set to old: */
+            write_locks[card_lock_idx] = mark_value;
+
+            uintptr_t start = get_card_index_to_index(card_index);
+            uintptr_t stop = get_card_index_to_index(card_index + 1);
+
+            dprintf(("trace_cards on %p with start:%lu stop:%lu\n",
+                     obj, start, stop));
+            stmcb_trace_cards(realobj, &minor_trace_if_young,
+                              start, stop);
+
+        }
+
+        /* all cards should be cleared on overflow objs */
+        assert(IMPLY(obj_is_overflow,
+                     write_locks[card_lock_idx] == CARD_CLEAR));
+
+        card_index++;
+    }
+    obj->stm_flags &= ~GCFLAG_CARDS_SET;
 }
 
 
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -225,8 +225,7 @@
    of CARD_SIZE. It can only be used on objects one any object, but only
    helps with those that were internally marked with GCFLAG_HAS_CARDS
    It has the same purpose as stm_write() for TM.
-   'index' is the byte-offset into the object divided by _STM_CARD_SIZE
-   plus 1: (offset // CARD_SIZE) + 1
+   'index' can be anything < size of the object
 */
 __attribute__((always_inline))
 static inline void stm_write_card(object_t *obj, uintptr_t index)
@@ -251,6 +250,12 @@
 */
 extern ssize_t stmcb_size_rounded_up(struct object_s *);
 extern void stmcb_trace(struct object_s *, void (object_t **));
+extern void stmcb_trace_cards(struct object_s *, void (object_t **),
+                              uintptr_t start, uintptr_t stop);
+/* needs to work with index > any valid index (can just return
+   object's size then) */
+extern uintptr_t stmcb_index_to_byte_offset(struct object_s *,
+                                            uintptr_t index);
 extern void stmcb_commit_soon(void);
 
 
diff --git a/c7/test/support.py b/c7/test/support.py
--- a/c7/test/support.py
+++ b/c7/test/support.py
@@ -76,7 +76,6 @@
 uint32_t _get_type_id(object_t *obj);
 void _set_ptr(object_t *obj, int n, object_t *v);
 object_t * _get_ptr(object_t *obj, int n);
-uintptr_t _index_to_card_index(object_t *obj, int n);
 
 void _set_weakref(object_t *obj, object_t *v);
 object_t* _get_weakref(object_t *obj);
@@ -268,16 +267,6 @@
     return *field;
 }
 
-uintptr_t _index_to_card_index(object_t *obj, int n)
-{
-    long nrefs = (long)((myobj_t*)obj)->type_id - 421420;
-    assert(n < nrefs);
-
-    stm_char *field_addr = NULL;
-    field_addr += SIZEOF_MYOBJ; /* header */
-    field_addr += n * sizeof(void*); /* field */
-    return ((uintptr_t)field_addr / _STM_CARD_SIZE) + 1;
-}
 
 ssize_t stmcb_size_rounded_up(struct object_s *obj)
 {
@@ -312,6 +301,32 @@
     }
 }
 
+void stmcb_trace_cards(struct object_s *obj, void visit(object_t **),
+                       uintptr_t start, uintptr_t stop)
+{
+    int i;
+    struct myobj_s *myobj = (struct myobj_s*)obj;
+    if (myobj->type_id < 421420) {
+        /* basic case: no references */
+        return;
+    }
+
+    for (i=start; (i < myobj->type_id - 421420) && (i < stop); i++) {
+        object_t **ref = ((object_t **)(myobj + 1)) + i;
+        visit(ref);
+    }
+}
+
+uintptr_t stmcb_index_to_byte_offset(struct object_s *obj, uintptr_t index)
+{
+    struct myobj_s *myobj = (struct myobj_s*)obj;
+    if (myobj->type_id < 421420) {
+        /* basic case: no references */
+        return sizeof(struct myobj_s) + index;
+    }
+    return sizeof(struct myobj_s) + index * sizeof(object_t*);
+}
+
 void stm_push_marker(stm_thread_local_t *tl, uintptr_t onum, object_t *ob)
 {
     STM_PUSH_MARKER(*tl, onum, ob);
@@ -358,8 +373,6 @@
 
 class EmptyStack(Exception):
     pass
-def byte_offset_to_card_index(offset):
-    return (offset // CARD_SIZE) + 1
 
 def is_in_nursery(o):
     return lib.stm_can_move(o)
@@ -402,7 +415,7 @@
 
 def stm_set_ref(obj, idx, ref, use_cards=False):
     if use_cards:
-        stm_write_card(obj, lib._index_to_card_index(obj, idx))
+        stm_write_card(obj, idx)
     else:
         stm_write(obj)
     lib._set_ptr(obj, idx, ref)
@@ -414,8 +427,7 @@
 def stm_set_char(obj, c, offset=HDR, use_cards=False):
     assert HDR <= offset < stm_get_obj_size(obj)
     if use_cards:
-        index = byte_offset_to_card_index(offset)
-        stm_write_card(obj, index)
+        stm_write_card(obj, offset)
     else:
         stm_write(obj)
     stm_get_real_address(obj)[offset] = c
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
@@ -55,41 +55,33 @@
         o = stm_allocate_old_refs(200)
         self.start_transaction()
         p = stm_allocate(64)
-        d = stm_allocate(64)
         stm_set_ref(o, 199, p, True)
 
         # without a write-barrier:
-        lib._set_ptr(o, 0, d)
+        lib._set_ptr(o, 0, ffi.cast("object_t*", -1))
 
         self.push_root(o)
         stm_minor_collect()
         o = self.pop_root()
 
+        lib._set_ptr(o, 0, ffi.NULL)
+
         pn = stm_get_ref(o, 199)
         assert not is_in_nursery(pn)
         assert pn != p
 
-        # d was not traced!
-        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)
+
         # without a write-barrier:
-        lib._set_ptr(o, 199, d2)
+        lib._set_ptr(o, 199, ffi.cast("object_t*", -1))
         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)
@@ -111,16 +103,16 @@
         assert not is_in_nursery(stm_get_ref(o, 100))
 
     def test_nursery3(self):
-        o = stm_allocate_old_refs(200)
+        o = stm_allocate_old_refs(2000)
         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, 1999, p, True)
         stm_set_ref(o, 1, d, True)
-        lib._set_ptr(o, 100, e) # no card marked!
+
+        lib._set_ptr(o, 1000, ffi.cast("object_t*", -1))
 
         assert not stm_was_written(o)
         assert stm_was_written_card(o)
@@ -129,9 +121,9 @@
         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, 1999))
         assert not is_in_nursery(stm_get_ref(o, 1))
-        assert stm_get_ref(o, 100) == e # not traced
+
 
     def test_abort_cleanup(self):
         o = stm_allocate_old_refs(200)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to