Author: Armin Rigo <[email protected]>
Branch: copy-over-original2
Changeset: r449:e35685ae86d0
Date: 2013-07-26 12:28 +0200
http://bitbucket.org/pypy/stmgc/changeset/e35685ae86d0/

Log:    Make two flags: VISITED vs MARKED. See doc in et.h.

diff --git a/c4/et.h b/c4/et.h
--- a/c4/et.h
+++ b/c4/et.h
@@ -25,7 +25,11 @@
  *
  * GCFLAG_OLD is set on old objects.
  *
- * GCFLAG_VISITED is used temporarily during major collections.
+ * GCFLAG_VISITED and GCFLAG_MARKED are used temporarily during major
+ * collections.  The objects are MARKED|VISITED as soon as they have been
+ * added to 'objects_to_trace', and so will be or have been traced.  The
+ * objects are only MARKED if their memory must be kept alive, but (so far)
+ * we found that tracing them is not useful.
  *
  * GCFLAG_PUBLIC is set on public objects.
  *
@@ -74,10 +78,12 @@
 static const revision_t GCFLAG_HAS_ID                 = STM_FIRST_GCFLAG << 10;
 static const revision_t GCFLAG_IMMUTABLE              = STM_FIRST_GCFLAG << 11;
 static const revision_t GCFLAG_SMALLSTUB              = STM_FIRST_GCFLAG << 12;
+static const revision_t GCFLAG_MARKED                 = STM_FIRST_GCFLAG << 13;
 
 
 /* this value must be reflected in PREBUILT_FLAGS in stmgc.h */
 #define GCFLAG_PREBUILT  (GCFLAG_VISITED           | \
+                          GCFLAG_MARKED            | \
                           GCFLAG_PREBUILT_ORIGINAL | \
                           GCFLAG_OLD               | \
                           GCFLAG_PUBLIC)
@@ -88,12 +94,14 @@
                          "PREBUILT_ORIGINAL", \
                          "PUBLIC_TO_PRIVATE", \
                          "WRITE_BARRIER",     \
-                         "MOVED",     \
+                         "MOVED",             \
                          "BACKUP_COPY",       \
                          "STUB",              \
                          "PRIVATE_FROM_PROTECTED", \
-                         "HAS_ID", \
-                         "IMMUTABLE", \
+                         "HAS_ID",            \
+                         "IMMUTABLE",         \
+                         "SMALLSTUB",         \
+                         "MARKED",            \
                          NULL }
 
 #define IS_POINTER(v)    (!((v) & 1))   /* even-valued number */
diff --git a/c4/gcpage.c b/c4/gcpage.c
--- a/c4/gcpage.c
+++ b/c4/gcpage.c
@@ -276,8 +276,12 @@
     if (obj->h_tid & GCFLAG_VISITED)
         return;        /* already visited */
 
-    obj->h_tid |= GCFLAG_VISITED;
+    obj->h_tid |= GCFLAG_VISITED | GCFLAG_MARKED;
     gcptrlist_insert2(&objects_to_trace, obj, (gcptr)gcp);
+
+    obj = (gcptr)obj->h_original;
+    if (obj != NULL)
+        obj->h_tid |= GCFLAG_MARKED;
 }
 
 static gcptr visit_public(gcptr obj, struct tx_public_descriptor *gcp)
@@ -369,7 +373,7 @@
         copy_over_original(obj, original);
 
     /* return this original */
-    original->h_tid |= GCFLAG_VISITED;
+    original->h_tid |= GCFLAG_VISITED | GCFLAG_MARKED;
     if (!(original->h_tid & GCFLAG_STUB))
         gcptrlist_insert2(&objects_to_trace, original, NULL);
     return original;
@@ -426,13 +430,15 @@
        contains all the ones that have been modified.  Because they are
        themselves not in any page managed by this file, their
        GCFLAG_VISITED is not removed at the end of the current
-       collection.  That's why we remove it here. */
+       collection.  That's why we remove it here.  GCFLAG_MARKED is not
+       relevant for prebuilt objects, but we avoid objects with MARKED
+       but not VISITED, which trigger some asserts. */
     gcptr *pobj = stm_prebuilt_gcroots.items;
     gcptr *pend = stm_prebuilt_gcroots.items + stm_prebuilt_gcroots.size;
     gcptr obj, obj2;
     for (; pobj != pend; pobj++) {
         obj = *pobj;
-        obj->h_tid &= ~GCFLAG_VISITED;
+        obj->h_tid &= ~(GCFLAG_VISITED | GCFLAG_MARKED);
         assert(obj->h_tid & GCFLAG_PREBUILT_ORIGINAL);
 
         obj2 = visit_public(obj, NULL);
@@ -680,7 +686,9 @@
            and the flag is removed; other locations are marked as free. */
         p = (gcptr)(lpage + 1);
         for (j = 0; j < objs_per_page; j++) {
-            if (p->h_tid & GCFLAG_VISITED)
+            assert(IMPLIES(p->h_tid & GCFLAG_VISITED,
+                           p->h_tid & GCFLAG_MARKED));
+            if (p->h_tid & GCFLAG_MARKED)
                 break;  /* first object that stays alive */
             p = (gcptr)(((char *)p) + obj_size);
         }
@@ -690,8 +698,10 @@
             surviving_pages = lpage;
             p = (gcptr)(lpage + 1);
             for (j = 0; j < objs_per_page; j++) {
-                if (p->h_tid & GCFLAG_VISITED) {
-                    p->h_tid &= ~GCFLAG_VISITED;
+                assert(IMPLIES(p->h_tid & GCFLAG_VISITED,
+                               p->h_tid & GCFLAG_MARKED));
+                if (p->h_tid & GCFLAG_MARKED) {
+                    p->h_tid &= ~(GCFLAG_VISITED | GCFLAG_MARKED);
                     mc_total_in_use += obj_size;
                 }
                 else {
@@ -717,6 +727,7 @@
             p = (gcptr)(lpage + 1);
             for (j = 0; j < objs_per_page; j++) {
                 assert(!(p->h_tid & GCFLAG_VISITED));
+                assert(!(p->h_tid & GCFLAG_MARKED));
                 if (p->h_tid != DEBUG_WORD(0xDD)) {
                     dprintf(("| freeing %p (with page %p)\n", p, lpage));
                 }
@@ -746,8 +757,10 @@
     G2L_LOOP_FORWARD(gcp->nonsmall_objects, item) {
 
         gcptr p = item->addr;
-        if (p->h_tid & GCFLAG_VISITED) {
-            p->h_tid &= ~GCFLAG_VISITED;
+        assert(IMPLIES(p->h_tid & GCFLAG_VISITED,
+                       p->h_tid & GCFLAG_MARKED));
+        if (p->h_tid & GCFLAG_MARKED) {
+            p->h_tid &= ~(GCFLAG_VISITED | GCFLAG_MARKED);
         }
         else {
             G2L_LOOP_DELETE(item);
diff --git a/c4/stmgc.h b/c4/stmgc.h
--- a/c4/stmgc.h
+++ b/c4/stmgc.h
@@ -23,7 +23,8 @@
 #define STM_SIZE_OF_USER_TID       (sizeof(revision_t) / 2)    /* in bytes */
 #define STM_FIRST_GCFLAG           (1L << (8 * STM_SIZE_OF_USER_TID))
 #define STM_USER_TID_MASK          (STM_FIRST_GCFLAG - 1)
-#define PREBUILT_FLAGS             (STM_FIRST_GCFLAG * (1 + 2 + 4 + 8))
+#define PREBUILT_FLAGS             (STM_FIRST_GCFLAG * ((1<<0) | (1<<1) |    \
+                                               (1<<2) | (1<<3) | (1<<13)))
 #define PREBUILT_REVISION          1
 
 
diff --git a/c4/test/test_extra.py b/c4/test/test_extra.py
--- a/c4/test/test_extra.py
+++ b/c4/test/test_extra.py
@@ -104,7 +104,7 @@
             assert ffi.string(c).endswith("ei424242ee")
 
 def test_pointer_equal():
-    p = palloc(HDR)
+    p = palloc(HDR + WORD)
     assert lib.stm_pointer_equal(p, p)
     assert not lib.stm_pointer_equal(p, ffi.NULL)
     assert not lib.stm_pointer_equal(ffi.NULL, p)
diff --git a/c4/test/test_gcpage.py b/c4/test/test_gcpage.py
--- a/c4/test/test_gcpage.py
+++ b/c4/test/test_gcpage.py
@@ -511,3 +511,24 @@
         #
         major_collect()
         check_free_old(p1)
+
+def test_keep_original_alive():
+    p2 = oalloc(HDR + WORD); make_public(p2)
+    p2b = lib.stm_write_barrier(p2)
+    lib.stm_push_root(p2)
+    minor_collect()
+    p2 = lib.stm_pop_root()
+    p2b = lib.stm_write_barrier(p2)
+    assert not lib.in_nursery(p2)
+    assert not lib.in_nursery(p2b)
+    lib.stm_commit_transaction()
+    lib.stm_begin_inevitable_transaction()
+    assert classify(p2) == "public"
+    assert classify(p2b) == "protected"
+    assert ffi.cast("gcptr", p2b.h_original) == p2
+    lib.stm_push_root(p2b)
+    major_collect()
+    p2c = lib.stm_pop_root()
+    check_not_free(ffi.cast("gcptr", p2c.h_original))
+    assert p2c == p2b
+    assert ffi.cast("gcptr", p2c.h_original) == p2
diff --git a/c4/test/test_nursery.py b/c4/test/test_nursery.py
--- a/c4/test/test_nursery.py
+++ b/c4/test/test_nursery.py
@@ -279,7 +279,7 @@
     assert classify(p2) == "private"
 
 def test_new_version():
-    p1 = oalloc(HDR)
+    p1 = oalloc(HDR + WORD)
     assert lib.stm_write_barrier(p1) == p1
     lib.stm_push_root(p1)
     transaction_break()
@@ -300,7 +300,7 @@
     assert classify(p2) == "private_from_protected"
 
 def test_prebuilt_version():
-    p1 = lib.pseudoprebuilt(HDR, 42 + HDR)
+    p1 = lib.pseudoprebuilt(HDR + WORD, 42 + HDR + WORD)
     p2 = lib.stm_write_barrier(p1)
     assert p2 != p1
     check_prebuilt(p1)
diff --git a/c4/weakref.c b/c4/weakref.c
--- a/c4/weakref.c
+++ b/c4/weakref.c
@@ -68,49 +68,25 @@
 
 static _Bool is_partially_visited(gcptr obj)
 {
-    /* Based on gcpage.c:visit().  Check the code here if we simplify
-       visit().  Returns True or False depending on whether we find any
+    /* Based on gcpage.c:visit_public().  Check the code here if we change
+       visit_public().  Returns True or False depending on whether we find any
        version of 'obj' to be VISITED or not.
     */
- restart:
+    assert(IMPLIES(obj->h_tid & GCFLAG_VISITED,
+                   obj->h_tid & GCFLAG_MARKED));
     if (obj->h_tid & GCFLAG_VISITED)
         return 1;
 
-    if (obj->h_revision & 1) {
-        assert(!(obj->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED));
-        assert(!(obj->h_tid & GCFLAG_STUB));
+    if (!(obj->h_tid & GCFLAG_PUBLIC))
         return 0;
-    }
-    else if (obj->h_tid & GCFLAG_PUBLIC) {
-        /* h_revision is a ptr: we have a more recent version */
-        if (!(obj->h_revision & 2)) {
-            /* go visit the more recent version */
-            obj = (gcptr)obj->h_revision;
-        }
-        else {
-            /* it's a stub */
-            assert(obj->h_tid & GCFLAG_STUB);
-            obj = (gcptr)(obj->h_revision - 2);
-        }
-        goto restart;
-    }
-    else {
-        assert(obj->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED);
-        gcptr B = (gcptr)obj->h_revision;
-        assert(B->h_tid & (GCFLAG_PUBLIC | GCFLAG_BACKUP_COPY));
-        if (B->h_tid & GCFLAG_VISITED)
+
+    if (obj->h_original != 0 &&
+            !(obj->h_tid & GCFLAG_PREBUILT_ORIGINAL)) {
+        gcptr original = (gcptr)obj->h_original;
+        assert(IMPLIES(original->h_tid & GCFLAG_VISITED,
+                       original->h_tid & GCFLAG_MARKED));
+        if (original->h_tid & GCFLAG_MARKED)
             return 1;
-        assert(!(obj->h_tid & GCFLAG_STUB));
-        assert(!(B->h_tid & GCFLAG_STUB));
-
-        if (IS_POINTER(B->h_revision)) {
-            assert(B->h_tid & GCFLAG_PUBLIC);
-            assert(!(B->h_tid & GCFLAG_BACKUP_COPY));
-            assert(!(B->h_revision & 2));
-
-            obj = (gcptr)B->h_revision;
-            goto restart;
-        }
     }
     return 0;
 }
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to