Author: Armin Rigo <[email protected]>
Branch: weakref
Changeset: r396:e0e0b65b0f26
Date: 2013-07-15 16:28 +0200
http://bitbucket.org/pypy/stmgc/changeset/e0e0b65b0f26/

Log:    Starting

diff --git a/c4/nursery.c b/c4/nursery.c
--- a/c4/nursery.c
+++ b/c4/nursery.c
@@ -54,6 +54,7 @@
 
     gcptrlist_delete(&d->old_objects_to_trace);
     gcptrlist_delete(&d->public_with_young_copy);
+    gcptrlist_delete(&d->young_weakrefs);
 }
 
 void stmgc_minor_collect_soon(void)
@@ -100,6 +101,15 @@
     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);
@@ -429,6 +439,19 @@
     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);
+        WEAKREF_PTR(weakref, size) = NULL;   /* XXX */
+    }
+}
+
 static void setup_minor_collect(struct tx_descriptor *d)
 {
     spinlock_acquire(d->public_descriptor->collection_lock, 'M');  /*minor*/
@@ -440,6 +463,7 @@
 {
     //assert(gcptrlist_size(&d->old_objects_to_trace) == 0);
     assert(gcptrlist_size(&d->public_with_young_copy) == 0);
+    assert(gcptrlist_size(&d->young_weakrefs) == 0);
     assert(gcptrlist_size(&d->public_descriptor->stolen_objects) == 0);
 
     spinlock_release(d->public_descriptor->collection_lock);
@@ -475,6 +499,8 @@
        surviving young-but-outside-the-nursery objects have been flagged
        with GCFLAG_OLD
     */
+    move_young_weakrefs(d);
+
     teardown_minor_collect(d);
     assert(!stm_has_got_any_lock(d));
 
@@ -541,6 +567,7 @@
         !g2l_any_entry(&d->young_objects_outside_nursery)*/ ) {
         /* there is no young object */
         assert(gcptrlist_size(&d->public_with_young_copy) == 0);
+        assert(gcptrlist_size(&d->young_weakrefs) == 0);
         assert(gcptrlist_size(&d->list_of_read_objects) >=
                d->num_read_objects_known_old);
         assert(gcptrlist_size(&d->private_from_protected) >=
diff --git a/c4/nursery.h b/c4/nursery.h
--- a/c4/nursery.h
+++ b/c4/nursery.h
@@ -50,7 +50,10 @@
        still in the same transaction, to know that the initial          \
        part of the lists cannot contain young objects any more. */      \
     long num_private_from_protected_known_old;                          \
-    long num_read_objects_known_old;
+    long num_read_objects_known_old;                                    \
+                                                                        \
+    /* Weakref support */                                               \
+    struct GcPtrList young_weakrefs;
 
 
 struct tx_descriptor;  /* from et.h */
@@ -65,4 +68,7 @@
 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.h b/c4/stmgc.h
--- a/c4/stmgc.h
+++ b/c4/stmgc.h
@@ -39,10 +39,8 @@
 _Bool stm_pointer_equal(gcptr, gcptr);
 
 /* to push/pop objects into the local shadowstack */
-#if 0     // (optimized version below)
-void stm_push_root(gcptr);
-gcptr stm_pop_root(void);
-#endif
+static inline void stm_push_root(gcptr);
+static inline gcptr stm_pop_root(void);
 
 /* initialize/deinitialize the stm framework in the current thread */
 void stm_initialize(void);
@@ -55,16 +53,14 @@
 void stm_leave_callback_call(int);
 
 /* read/write barriers (the most general versions only for now) */
-#if 0     // (optimized version below)
-gcptr stm_read_barrier(gcptr);
-gcptr stm_write_barrier(gcptr);
-#endif
+static inline gcptr stm_read_barrier(gcptr);
+static inline gcptr stm_write_barrier(gcptr);
 
 /* start a new transaction, calls callback(), and when it returns
    finish that transaction.  callback() is called with the 'arg'
    provided, and with a retry_counter number.  Must save roots around
-   this call.  The callback() is called repeatedly as long as it
-   returns a value > 0. */
+   this call.  If callback() returns a value > 0, it is called
+   again. */
 void stm_perform_transaction(gcptr arg, int (*callback)(gcptr, int));
 
 /* finish the current transaction, start a new one, or turn the current
@@ -114,6 +110,12 @@
 void stm_minor_collect(void);
 void stm_major_collect(void);
 
+/* weakref support: allocate a weakref object, and set it to point
+   weakly to 'obj'.  The weak pointer offset is hard-coded to be at
+   'size - WORD'.  Important: stmcb_trace() must NOT trace it. */
+gcptr stm_weakref_allocate(size_t size, unsigned long tid, gcptr obj);
+
+
 
 /****************  END OF PUBLIC INTERFACE  *****************/
 /************************************************************/
diff --git a/c4/test/support.py b/c4/test/support.py
--- a/c4/test/support.py
+++ b/c4/test/support.py
@@ -46,7 +46,7 @@
     #define PREBUILT_FLAGS         ...
     #define PREBUILT_REVISION      ...
 
-    gcptr stm_allocate(size_t size, unsigned int tid);
+    gcptr stm_allocate(size_t size, unsigned long tid);
     revision_t stm_hash(gcptr);
     revision_t stm_id(gcptr);
     _Bool stm_pointer_equal(gcptr, gcptr);
@@ -69,6 +69,7 @@
     void stm_abort_info_pop(long count);
     char *stm_inspect_abort_info(void);
     void stm_abort_and_retry(void);
+    gcptr stm_weakref_allocate(size_t size, unsigned long tid, gcptr obj);
 
     /* extra non-public code */
     void printfcolor(char *msg);
@@ -164,14 +165,18 @@
 
     gcptr rawgetptr(gcptr obj, long index)
     {
-        assert(gettid(obj) > 42142 + index);
+        revision_t t = gettid(obj);
+        if (t == 42142) t++;
+        assert(t > 42142 + index);
         return ((gcptr *)(obj + 1))[index];
     }
 
     void rawsetptr(gcptr obj, long index, gcptr newvalue)
     {
         fprintf(stderr, "%p->[%ld] = %p\n", obj, index, newvalue);
-        assert(gettid(obj) > 42142 + index);
+        revision_t t = gettid(obj);
+        if (t == 42142) t++;
+        assert(t > 42142 + index);
         ((gcptr *)(obj + 1))[index] = newvalue;
     }
 
@@ -282,6 +287,8 @@
         else {
             int nrefs = gettid(obj) - 42142;
             assert(nrefs < 100);
+            if (nrefs == 0)   /* weakrefs */
+                nrefs = 1;
             return sizeof(*obj) + nrefs * sizeof(gcptr);
         }
     }
@@ -484,7 +491,7 @@
 def oalloc_refs(nrefs):
     """Allocate an 'old' protected object, outside any nursery,
     with nrefs pointers"""
-    size = HDR + WORD * nrefs
+    size = HDR + WORD * (nrefs or 1)
     p = lib.stmgcpage_malloc(size)
     lib.memset(p, 0, size)
     p.h_tid = GCFLAG_OLD | GCFLAG_WRITE_BARRIER
@@ -506,9 +513,9 @@
 
 def nalloc_refs(nrefs):
     "Allocate a fresh object from the nursery, with nrefs pointers"
-    p = lib.stm_allocate(HDR + WORD * nrefs, 42142 + nrefs)
+    p = lib.stm_allocate(HDR + WORD * (nrefs or 1), 42142 + nrefs)
     assert p.h_revision == lib.get_private_rev_num()
-    for i in range(nrefs):
+    for i in range(nrefs or 1):
         assert rawgetptr(p, i) == ffi.NULL   # must already be zero-filled
     return p
 
@@ -524,9 +531,9 @@
 def palloc_refs(nrefs, prehash=None):
     "Get a ``prebuilt'' object with nrefs pointers."
     if prehash is None:
-        p = lib.pseudoprebuilt(HDR + WORD * nrefs, 42142 + nrefs)
+        p = lib.pseudoprebuilt(HDR + WORD * (nrefs or 1), 42142 + nrefs)
     else:
-        p = lib.pseudoprebuilt_with_hash(HDR + WORD * nrefs,
+        p = lib.pseudoprebuilt_with_hash(HDR + WORD * (nrefs or 1),
                                          42142 + nrefs, prehash)
     return p
 
@@ -684,5 +691,8 @@
 
 should_break_transaction = lib.stm_should_break_transaction
 
-    
+WEAKREF_SIZE = HDR + WORD
+WEAKREF_TID  = 42142
+
+
 nrb_protected = ffi.cast("gcptr", -1)
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,3 +319,14 @@
 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
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to