Author: Armin Rigo <[email protected]>
Branch: weakref
Changeset: r406:698e0c3f3413
Date: 2013-07-17 18:47 +0200
http://bitbucket.org/pypy/stmgc/changeset/698e0c3f3413/

Log:    In-progress: move the weakref code in its own file, and start
        writing logic for major collections.

diff --git a/c4/Makefile b/c4/Makefile
--- a/c4/Makefile
+++ b/c4/Makefile
@@ -16,10 +16,10 @@
 
 H_FILES = atomic_ops.h stmgc.h stmimpl.h \
          et.h lists.h steal.h nursery.h gcpage.h \
-          stmsync.h extra.h dbgmem.h fprintcolor.h
+          stmsync.h extra.h weakref.h dbgmem.h fprintcolor.h
 
 C_FILES = et.c lists.c steal.c nursery.c gcpage.c \
-          stmsync.c extra.c dbgmem.c fprintcolor.c
+          stmsync.c extra.c weakref.c dbgmem.c fprintcolor.c
 
 DEBUG = -g -DGC_NURSERY=0x10000 -D_GC_DEBUG=1 -DDUMP_EXTRA=1 
-D_GC_DEBUGPRINTS=1
 
diff --git a/c4/gcpage.c b/c4/gcpage.c
--- a/c4/gcpage.c
+++ b/c4/gcpage.c
@@ -649,6 +649,8 @@
     int i;
     wlog_t *item;
 
+    stm_invalidate_old_weakrefs(gcp);
+
     for (i = 1; i < GC_SMALL_REQUESTS; i++) {
         sweep_pages(gcp, i);
     }
diff --git a/c4/gcpage.h b/c4/gcpage.h
--- a/c4/gcpage.h
+++ b/c4/gcpage.h
@@ -45,7 +45,8 @@
 
 /* These fields are in tx_public_descriptor rather than tx_descriptor.
    The indirection allows us to keep around the lists of pages even
-   after the thread finishes, until the next major collection.
+   after the thread finishes.  Such a "zombie" tx_public_descriptor
+   is reused by the next thread that starts.
 */
 #define GCPAGE_FIELDS_DECL                                              \
     /* The array 'pages_for_size' contains GC_SMALL_REQUESTS            \
@@ -65,7 +66,10 @@
     /* A set of all non-small objects (outside the nursery).            \
        We could also have a single global set, but this avoids          \
        locking in stmgcpage_malloc/free. */                             \
-    struct G2L nonsmall_objects;
+    struct G2L nonsmall_objects;                                        \
+                                                                        \
+    /* Weakref support */                                               \
+    struct GcPtrList old_weakrefs;
 
 
 #define LOCAL_GCPAGES()  (thread_descriptor->public_descriptor)
diff --git a/c4/nursery.c b/c4/nursery.c
--- a/c4/nursery.c
+++ b/c4/nursery.c
@@ -101,15 +101,6 @@
     return P;
 }
 
-gcptr stm_weakref_allocate(size_t size, unsigned long tid, gcptr obj)
-{
-    gcptr weakref = stm_allocate(size, tid);
-    assert(stmgc_size(weakref) == size);
-    WEAKREF_PTR(weakref, size) = obj;
-    gcptrlist_insert(&thread_descriptor->young_weakrefs, weakref);
-    return weakref;
-}
-
 gcptr stmgc_duplicate(gcptr P)
 {
     size_t size = stmgc_size(P);
@@ -439,27 +430,6 @@
     fxcache_clear(&d->recent_reads_cache);
 }
 
-static void move_young_weakrefs(struct tx_descriptor *d)
-{
-    while (gcptrlist_size(&d->young_weakrefs) > 0) {
-        gcptr weakref = gcptrlist_pop(&d->young_weakrefs);
-        if (!(weakref->h_tid & GCFLAG_NURSERY_MOVED))
-            continue;   /* the weakref itself dies */
-
-        weakref = (gcptr)weakref->h_revision;
-        size_t size = stmgc_size(weakref);
-        gcptr obj = WEAKREF_PTR(weakref, size);
-        if (!is_in_nursery(d, obj))
-            continue;   /* the pointer does not change */
-
-        if (obj->h_tid & GCFLAG_NURSERY_MOVED)
-            obj = obj->h_revision;
-        else
-            obj = NULL;
-        WEAKREF_PTR(weakref, size) = obj;
-    }
-}
-
 static void setup_minor_collect(struct tx_descriptor *d)
 {
     spinlock_acquire(d->public_descriptor->collection_lock, 'M');  /*minor*/
@@ -507,7 +477,7 @@
        surviving young-but-outside-the-nursery objects have been flagged
        with GCFLAG_OLD
     */
-    move_young_weakrefs(d);
+    stm_move_young_weakrefs(d);
 
     teardown_minor_collect(d);
     assert(!stm_has_got_any_lock(d));
diff --git a/c4/nursery.h b/c4/nursery.h
--- a/c4/nursery.h
+++ b/c4/nursery.h
@@ -68,7 +68,4 @@
 void stmgc_trace(gcptr, void visit(gcptr *));
 void stmgc_minor_collect_soon(void);
 
-#define WEAKREF_PTR(wr, sz)  (*(gcptr *)(((char *)(wr)) + (sz) - WORD))
-
-
 #endif
diff --git a/c4/stmgc.c b/c4/stmgc.c
--- a/c4/stmgc.c
+++ b/c4/stmgc.c
@@ -10,5 +10,6 @@
 #include "gcpage.c"
 #include "stmsync.c"
 #include "extra.c"
+#include "weakref.c"
 #include "dbgmem.c"
 #include "fprintcolor.c"
diff --git a/c4/stmimpl.h b/c4/stmimpl.h
--- a/c4/stmimpl.h
+++ b/c4/stmimpl.h
@@ -36,5 +36,6 @@
 #include "steal.h"
 #include "stmsync.h"
 #include "extra.h"
+#include "weakref.h"
 
 #endif
diff --git a/c4/test/support.py b/c4/test/support.py
--- a/c4/test/support.py
+++ b/c4/test/support.py
@@ -11,11 +11,11 @@
 
 header_files = [os.path.join(parent_dir, _n) for _n in
                 "et.h lists.h steal.h nursery.h gcpage.h "
-                "stmsync.h extra.h dbgmem.h fprintcolor.h "
+                "stmsync.h extra.h weakref.h dbgmem.h fprintcolor.h "
                 "stmgc.h stmimpl.h atomic_ops.h".split()]
 source_files = [os.path.join(parent_dir, _n) for _n in
                 "et.c lists.c steal.c nursery.c gcpage.c "
-                "stmsync.c extra.c dbgmem.c fprintcolor.c".split()]
+                "stmsync.c extra.c weakref.c dbgmem.c fprintcolor.c".split()]
 
 _pycache_ = os.path.join(parent_dir, 'test', '__pycache__')
 if os.path.exists(_pycache_):
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
@@ -319,45 +319,3 @@
 def test_collect_soon():
     lib.stmgc_minor_collect_soon()
     nalloc(HDR)
-
-def test_weakref_invalidate():
-    p2 = nalloc(HDR)
-    p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
-    assert p1.h_tid == WEAKREF_TID   # no GC flags
-    assert p1.h_revision == lib.get_private_rev_num()
-    assert lib.rawgetptr(p1, 0) == p2
-    lib.stm_push_root(p1)
-    minor_collect()
-    p1 = lib.stm_pop_root()
-    assert lib.rawgetptr(p1, 0) == ffi.NULL
-
-def test_weakref_itself_dies():
-    p2 = nalloc(HDR)
-    p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
-    minor_collect()
-
-def test_weakref_keep():
-    p2 = nalloc(HDR)
-    p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
-    assert p1.h_tid == WEAKREF_TID   # no GC flags
-    assert p1.h_revision == lib.get_private_rev_num()
-    assert lib.rawgetptr(p1, 0) == p2
-    lib.stm_push_root(p1)
-    lib.stm_push_root(p2)
-    minor_collect()
-    p2 = lib.stm_pop_root()
-    p1 = lib.stm_pop_root()
-    assert lib.rawgetptr(p1, 0) == p2
-
-def test_weakref_old_keep():
-    p2 = oalloc(HDR)
-    p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
-    assert p1.h_tid == WEAKREF_TID   # no GC flags
-    assert p1.h_revision == lib.get_private_rev_num()
-    assert lib.rawgetptr(p1, 0) == p2
-    lib.stm_push_root(p1)
-    lib.stm_push_root(p2)
-    minor_collect()
-    p2 = lib.stm_pop_root()
-    p1 = lib.stm_pop_root()
-    assert lib.rawgetptr(p1, 0) == p2
diff --git a/c4/test/test_weakref.py b/c4/test/test_weakref.py
new file mode 100644
--- /dev/null
+++ b/c4/test/test_weakref.py
@@ -0,0 +1,120 @@
+import py
+from support import *
+
+
+class BaseTest(object):
+    def setup_method(self, meth):
+        lib.stm_clear_between_tests()
+        lib.stm_initialize_tests(0)
+    def teardown_method(self, meth):
+        lib.stm_finalize()
+
+
+class TestMinorCollection(BaseTest):
+
+    def test_weakref_invalidate(self):
+        p2 = nalloc(HDR)
+        p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
+        assert p1.h_tid == WEAKREF_TID   # no GC flags
+        assert p1.h_revision == lib.get_private_rev_num()
+        assert lib.rawgetptr(p1, 0) == p2
+        lib.stm_push_root(p1)
+        minor_collect()
+        p1 = lib.stm_pop_root()
+        assert lib.rawgetptr(p1, 0) == ffi.NULL
+
+    def test_weakref_itself_dies(self):
+        p2 = nalloc(HDR)
+        p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
+        minor_collect()
+
+    def test_weakref_keep(self):
+        p2 = nalloc(HDR)
+        p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
+        assert p1.h_tid == WEAKREF_TID   # no GC flags
+        assert p1.h_revision == lib.get_private_rev_num()
+        assert lib.rawgetptr(p1, 0) == p2
+        lib.stm_push_root(p1)
+        lib.stm_push_root(p2)
+        minor_collect()
+        p2 = lib.stm_pop_root()
+        p1 = lib.stm_pop_root()
+        assert lib.rawgetptr(p1, 0) == p2
+
+    def test_weakref_old_keep(self):
+        p2 = oalloc(HDR)
+        p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
+        assert p1.h_tid == WEAKREF_TID   # no GC flags
+        assert p1.h_revision == lib.get_private_rev_num()
+        assert lib.rawgetptr(p1, 0) == p2
+        lib.stm_push_root(p1)
+        lib.stm_push_root(p2)
+        minor_collect()
+        p2 = lib.stm_pop_root()
+        p1 = lib.stm_pop_root()
+        assert lib.rawgetptr(p1, 0) == p2
+
+
+class TestMajorCollection(BaseTest):
+
+    def test_weakref_old(self):
+        p2 = nalloc(HDR)
+        p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
+        #
+        lib.stm_push_root(p1)
+        lib.stm_push_root(p2)
+        major_collect()
+        p2 = lib.stm_pop_root()
+        p1 = lib.stm_pop_root()
+        assert lib.rawgetptr(p1, 0) == p2
+        #
+        lib.stm_push_root(p1)
+        major_collect()
+        p1 = lib.stm_pop_root()
+        assert lib.rawgetptr(p1, 0) == ffi.NULL
+
+    def test_weakref_to_prebuilt(self):
+        p2 = palloc(HDR)
+        p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
+        #
+        lib.stm_push_root(p1)
+        major_collect()
+        p1 = lib.stm_pop_root()
+        assert lib.rawgetptr(p1, 0) == p2
+
+    def test_weakref_update_version(self):
+        p2 = oalloc(HDR + WORD); make_public(p2)
+        p1 = lib.stm_weakref_allocate(WEAKREF_SIZE, WEAKREF_TID, p2)
+        #
+        lib.stm_push_root(p1)
+        lib.stm_push_root(p2)
+        major_collect()
+        p2 = lib.stm_pop_root()
+        p1 = lib.stm_pop_root()
+        assert lib.rawgetptr(p1, 0) == p2
+        #
+        lib.stm_commit_transaction()
+        lib.stm_begin_inevitable_transaction()
+        #
+        lib.setlong(p2, 0, 912809218)   # write barrier
+        assert lib.rawgetlong(p2, 0) == 0
+        lib.stm_push_root(p1)
+        lib.stm_push_root(p2)
+        major_collect()
+        p2 = lib.stm_pop_root()
+        p1 = lib.stm_pop_root()
+        assert lib.rawgetptr(p1, 0) == p2
+        assert lib.rawgetlong(p2, 0) == 0
+        #
+        lib.stm_commit_transaction()
+        lib.stm_begin_inevitable_transaction()
+        #
+        assert lib.rawgetlong(p2, 0) == 0
+        lib.stm_push_root(p1)
+        lib.stm_push_root(p2)
+        major_collect()
+        p2b = lib.stm_pop_root()
+        p1 = lib.stm_pop_root()
+        assert lib.rawgetptr(p1, 0) == p2
+        assert p2b != p2
+        assert lib.rawgetlong(p2b, 0) == 912809218
diff --git a/c4/weakref.c b/c4/weakref.c
new file mode 100644
--- /dev/null
+++ b/c4/weakref.c
@@ -0,0 +1,92 @@
+#include "stmimpl.h"
+
+#define WEAKREF_PTR(wr, sz)  (*(gcptr *)(((char *)(wr)) + (sz) - WORD))
+
+
+gcptr stm_weakref_allocate(size_t size, unsigned long tid, gcptr obj)
+{
+    gcptr weakref = stm_allocate(size, tid);
+    assert(!(weakref->h_tid & GCFLAG_OLD));   /* 'size' too big? */
+    assert(stmgc_size(weakref) == size);
+    WEAKREF_PTR(weakref, size) = obj;
+    gcptrlist_insert(&thread_descriptor->young_weakrefs, weakref);
+    return weakref;
+}
+
+
+/***** Minor collection *****/
+
+static int is_in_nursery(struct tx_descriptor *d, gcptr obj)
+{
+    return (d->nursery_base <= (char*)obj && ((char*)obj) < d->nursery_end);
+}
+
+void stm_move_young_weakrefs(struct tx_descriptor *d)
+{
+    /* The code relies on the fact that no weakref can be an old object
+       weakly pointing to a young object.  Indeed, weakrefs are immutable
+       so they cannot point to an object that was created after it.
+    */
+    while (gcptrlist_size(&d->young_weakrefs) > 0) {
+        gcptr weakref = gcptrlist_pop(&d->young_weakrefs);
+        if (!(weakref->h_tid & GCFLAG_NURSERY_MOVED))
+            continue;   /* the weakref itself dies */
+
+        weakref = (gcptr)weakref->h_revision;
+        size_t size = stmgc_size(weakref);
+        gcptr pointing_to = WEAKREF_PTR(weakref, size);
+        assert(pointing_to != NULL);
+
+        if (is_in_nursery(d, pointing_to)) {
+            if (pointing_to->h_tid & GCFLAG_NURSERY_MOVED) {
+                WEAKREF_PTR(weakref, size) = (gcptr)pointing_to->h_revision;
+            }
+            else {
+                WEAKREF_PTR(weakref, size) = NULL;
+                continue;   /* no need to remember this weakref any longer */
+            }
+        }
+        else {
+            /*  # see test_weakref_to_prebuilt: it's not useful to put
+                # weakrefs into 'old_objects_with_weakrefs' if they point
+                # to a prebuilt object (they are immortal).  If moreover
+                # the 'pointing_to' prebuilt object still has the
+                # GCFLAG_NO_HEAP_PTRS flag, then it's even wrong, because
+                # 'pointing_to' will not get the GCFLAG_VISITED during
+                # the next major collection.  Solve this by not registering
+                # the weakref into 'old_objects_with_weakrefs'.
+            */
+        }
+        gcptrlist_insert(&d->public_descriptor->old_weakrefs, weakref);
+    }
+}
+
+
+/***** Major collection *****/
+
+void stm_invalidate_old_weakrefs(struct tx_public_descriptor *gcp)
+{
+    /* walk over list of objects that contain weakrefs.  If the
+       object it references does not survive, invalidate the weakref */
+    long i;
+    gcptr *items = gcp->old_weakrefs.items;
+
+    for (i = gcp->old_weakrefs.size - 1; i >= 0; i--) {
+        gcptr weakref = items[i];
+
+        if (!(weakref->h_tid & GCFLAG_VISITED)) {
+            /* weakref itself dies */
+        }
+        else {
+            size_t size = stmgc_size(weakref);
+            gcptr pointing_to = WEAKREF_PTR(weakref, size);
+            //...;
+            abort();
+        }
+
+        /* remove this weakref from the list */
+        items[i] = items[--gcp->old_weakrefs.size];
+    }
+
+    gcptrlist_compress(&gcp->old_weakrefs);
+}
diff --git a/c4/weakref.h b/c4/weakref.h
new file mode 100644
--- /dev/null
+++ b/c4/weakref.h
@@ -0,0 +1,9 @@
+#ifndef _SRCSTM_WEAKREF_H
+#define _SRCSTM_WEAKREF_H
+
+
+void stm_move_young_weakrefs(struct tx_descriptor *);
+void stm_invalidate_old_weakrefs(struct tx_public_descriptor *);
+
+
+#endif
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to