Author: Armin Rigo <ar...@tunes.org>
Branch: 
Changeset: r958:cb55e6140145
Date: 2014-03-05 10:10 +0100
http://bitbucket.org/pypy/stmgc/changeset/cb55e6140145/

Log:    Finish copying the shadow logic from pypy.

diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -36,7 +36,7 @@
        by finding that we already own the write-lock. */
     uintptr_t lock_idx = (((uintptr_t)obj) >> 4) - WRITELOCK_START;
     uint8_t lock_num = STM_PSEGMENT->write_lock_num;
-    assert((intptr_t)lock_idx >= 0);
+    assert(lock_idx < sizeof(write_locks));
  retry:
     if (write_locks[lock_idx] == 0) {
         if (UNLIKELY(!__sync_bool_compare_and_swap(&write_locks[lock_idx],
@@ -179,6 +179,7 @@
 
     assert(list_is_empty(STM_PSEGMENT->modified_old_objects));
     assert(tree_is_cleared(STM_PSEGMENT->young_outside_nursery));
+    assert(tree_is_cleared(STM_PSEGMENT->nursery_objects_shadows));
     assert(STM_PSEGMENT->objects_pointing_to_nursery == NULL);
     assert(STM_PSEGMENT->large_overflow_objects == NULL);
 
@@ -300,7 +301,7 @@
             /* clear the write-lock (note that this runs with all other
                threads paused, so no need to be careful about ordering) */
             uintptr_t lock_idx = (((uintptr_t)item) >> 4) - WRITELOCK_START;
-            assert((intptr_t)lock_idx >= 0);
+            assert(lock_idx < sizeof(write_locks));
             assert(write_locks[lock_idx] == STM_PSEGMENT->write_lock_num);
             write_locks[lock_idx] = 0;
 
@@ -371,7 +372,8 @@
     /* update 'overflow_number' if needed */
     if (STM_PSEGMENT->overflow_number_has_been_used) {
         highest_overflow_number += GCFLAG_OVERFLOW_NUMBER_bit0;
-        assert(highest_overflow_number != 0);   /* XXX else, overflow! */
+        assert(highest_overflow_number !=        /* XXX else, overflow! */
+               (uint32_t)-GCFLAG_OVERFLOW_NUMBER_bit0);
         STM_PSEGMENT->overflow_number = highest_overflow_number;
         STM_PSEGMENT->overflow_number_has_been_used = false;
     }
@@ -440,7 +442,7 @@
 
             /* clear the write-lock */
             uintptr_t lock_idx = (((uintptr_t)item) >> 4) - WRITELOCK_START;
-            assert((intptr_t)lock_idx >= 0);
+            assert(lock_idx < sizeof(write_locks));
             assert(write_locks[lock_idx] == pseg->write_lock_num);
             write_locks[lock_idx] = 0;
         }));
diff --git a/c7/stm/core.h b/c7/stm/core.h
--- a/c7/stm/core.h
+++ b/c7/stm/core.h
@@ -95,11 +95,16 @@
        current transaction spanned a minor collection. */
     struct list_s *large_overflow_objects;
 
-    /* List of all young objects outside the nursery ("young" in the
+    /* Set of all young objects outside the nursery ("young" in the
        sense that they should be in the nursery, but were too big for
        that). */
     struct tree_s *young_outside_nursery;
 
+    /* Support for id and identityhash: this is a dict mapping nursery
+       objects with GCFLAG_HAS_SHADOW to their future location at the
+       next minor collection. */
+    struct tree_s *nursery_objects_shadows;
+
     /* Start time: to know approximately for how long a transaction has
        been running, in contention management */
     uint64_t start_time;
diff --git a/c7/stm/gcpage.c b/c7/stm/gcpage.c
--- a/c7/stm/gcpage.c
+++ b/c7/stm/gcpage.c
@@ -151,7 +151,6 @@
 static inline uintptr_t mark_loc(object_t *obj)
 {
     uintptr_t lock_idx = (((uintptr_t)obj) >> 4) - WRITELOCK_START;
-    assert(lock_idx >= 0);
     assert(lock_idx < sizeof(write_locks));
     return lock_idx;
 }
diff --git a/c7/stm/hash_id.c b/c7/stm/hash_id.c
--- a/c7/stm/hash_id.c
+++ b/c7/stm/hash_id.c
@@ -17,7 +17,7 @@
 
     if (obj != NULL) {
         if (_is_in_nursery(obj)) {
-            abort();//obj = find_shadow(obj);
+            obj = find_shadow(obj);
         }
         else if (is_hash) {
             if (obj->stm_flags & GCFLAG_HAS_SHADOW) {
diff --git a/c7/stm/nursery.c b/c7/stm/nursery.c
--- a/c7/stm/nursery.c
+++ b/c7/stm/nursery.c
@@ -53,10 +53,12 @@
     return _is_in_nursery(obj);
 }
 
+static object_t *find_existing_shadow(object_t *obj);
+
 
 /************************************************************/
 
-#define GCWORD_MOVED  ((object_t *) -42)
+#define GCWORD_MOVED  ((object_t *) -1)
 #define FLAG_SYNC_LARGE       0x01
 
 
@@ -76,18 +78,33 @@
            to GCWORD_MOVED.  In that case, the forwarding location, i.e.
            where the object moved to, is stored in the second word in 'obj'. */
         object_t *TLPREFIX *pforwarded_array = (object_t *TLPREFIX *)obj;
+        char *realobj;
+        size_t size;
 
-        if (pforwarded_array[0] == GCWORD_MOVED) {
-            *pobj = pforwarded_array[1];    /* already moved */
-            return;
+        if (obj->stm_flags & GCFLAG_HAS_SHADOW) {
+            /* ^^ the single check above detects both already-moved objects
+               and objects with HAS_SHADOW.  This is because GCWORD_MOVED
+               overrides completely the stm_flags field with 1's bits. */
+
+            if (LIKELY(pforwarded_array[0] == GCWORD_MOVED)) {
+                *pobj = pforwarded_array[1];    /* already moved */
+                return;
+            }
+            else {
+                /* really has a shadow */
+                nobj = find_existing_shadow(obj);
+                obj->stm_flags &= ~GCFLAG_HAS_SHADOW;
+                realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
+                size = stmcb_size_rounded_up((struct object_s *)realobj);
+                goto copy_large_object;
+            }
         }
-
         /* We need to make a copy of this object.  It goes either in
            a largemalloc.c-managed area, or if it's small enough, in
            one of the small uniform pages from gcpage.c.
         */
-        char *realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
-        size_t size = stmcb_size_rounded_up((struct object_s *)realobj);
+        realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
+        size = stmcb_size_rounded_up((struct object_s *)realobj);
 
         if (1 /*size >= GC_N_SMALL_REQUESTS*8*/) {
 
@@ -97,6 +114,7 @@
             nobj = (object_t *)(allocated - stm_object_pages);
 
             /* Copy the object */
+         copy_large_object:;
             char *realnobj = REAL_ADDRESS(STM_SEGMENT->segment_base, nobj);
             memcpy(realnobj, realobj, size);
 
@@ -229,6 +247,8 @@
 
         tree_clear(pseg->young_outside_nursery);
     }
+
+    tree_clear(pseg->nursery_objects_shadows);
 }
 
 #define MINOR_NOTHING_TO_DO(pseg)                                       \
@@ -340,7 +360,7 @@
 
     char *result = allocate_outside_nursery_large(size_rounded_up);
     object_t *o = (object_t *)(result - stm_object_pages);
-    tree_insert(STM_PSEGMENT->young_outside_nursery, (intptr_t)o, 0);
+    tree_insert(STM_PSEGMENT->young_outside_nursery, (uintptr_t)o, 0);
 
     memset(REAL_ADDRESS(STM_SEGMENT->segment_base, o), 0, size_rounded_up);
     return o;
@@ -413,3 +433,60 @@
 
     set_gs_register(get_segment_base(original_num));
 }
+
+static object_t *allocate_shadow(object_t *obj)
+{
+    char *realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
+    size_t size = stmcb_size_rounded_up((struct object_s *)realobj);
+
+    /* always gets outside as a large object for now */
+    char *allocated = allocate_outside_nursery_large(size);
+    object_t *nobj = (object_t *)(allocated - stm_object_pages);
+
+    /* Initialize the shadow enough to be considered a valid gc object.
+       If the original object stays alive at the next minor collection,
+       it will anyway be copied over the shadow and overwrite the
+       following fields.  But if the object dies, then the shadow will
+       stay around and only be freed at the next major collection, at
+       which point we want it to look valid (but ready to be freed).
+
+       Here, in the general case, it requires copying the whole object.
+       It could be more optimized in special cases like in PyPy, by
+       copying only the typeid and (for var-sized objects) the length
+       field.  It's probably overkill to add a special stmcb_xxx
+       interface just for that.
+    */
+    char *realnobj = REAL_ADDRESS(STM_SEGMENT->segment_base, nobj);
+    memcpy(realnobj, realobj, size);
+
+    obj->stm_flags |= GCFLAG_HAS_SHADOW;
+    tree_insert(STM_PSEGMENT->nursery_objects_shadows,
+                (uintptr_t)obj, (uintptr_t)nobj);
+    return nobj;
+}
+
+static object_t *find_existing_shadow(object_t *obj)
+{
+    wlog_t *item;
+
+    TREE_FIND(*STM_PSEGMENT->nursery_objects_shadows,
+              (uintptr_t)obj, item, goto not_found);
+
+    /* The answer is the address of the shadow. */
+    return (object_t *)item->val;
+
+ not_found:
+    stm_fatalerror("GCFLAG_HAS_SHADOW but no shadow found");
+}
+
+static object_t *find_shadow(object_t *obj)
+{
+    /* The object 'obj' is still in the nursery.  Find or allocate a
+        "shadow" object, which is where the object will be moved by the
+        next minor collection
+    */
+    if (obj->stm_flags & GCFLAG_HAS_SHADOW)
+        return find_existing_shadow(obj);
+    else
+        return allocate_shadow(obj);
+}
diff --git a/c7/stm/nursery.h b/c7/stm/nursery.h
--- a/c7/stm/nursery.h
+++ b/c7/stm/nursery.h
@@ -19,3 +19,5 @@
 }
 
 static void assert_memset_zero(void *s, size_t n);
+
+static object_t *find_shadow(object_t *obj);
diff --git a/c7/stm/setup.c b/c7/stm/setup.c
--- a/c7/stm/setup.c
+++ b/c7/stm/setup.c
@@ -58,6 +58,7 @@
         pr->large_overflow_objects = NULL;
         pr->modified_old_objects = list_create();
         pr->young_outside_nursery = tree_create();
+        pr->nursery_objects_shadows = tree_create();
         pr->overflow_number = GCFLAG_OVERFLOW_NUMBER_bit0 * (i + 1);
         highest_overflow_number = pr->overflow_number;
     }
@@ -94,6 +95,7 @@
         assert(pr->large_overflow_objects == NULL);
         list_free(pr->modified_old_objects);
         tree_free(pr->young_outside_nursery);
+        tree_free(pr->nursery_objects_shadows);
     }
 
     munmap(stm_object_pages, TOTAL_MEMORY);
diff --git a/c7/test/test_hash_id.py b/c7/test/test_hash_id.py
--- a/c7/test/test_hash_id.py
+++ b/c7/test/test_hash_id.py
@@ -37,3 +37,38 @@
         h2 = lib.stm_id(lp2)
         assert h1 == int(ffi.cast("long", lp1))
         assert h2 == int(ffi.cast("long", lp2))
+
+    def test_hash_nursery(self):
+        self.start_transaction()
+        lp1 = stm_allocate(16)
+        lp2 = stm_allocate(16)
+        lp3 = stm_allocate(16)
+        lp4 = stm_allocate(16)
+        h1 = lib.stm_identityhash(lp1)
+        h2 = lib.stm_identityhash(lp2)
+        h3 = lib.stm_identityhash(lp3)
+        h4 = lib.stm_identityhash(lp4)
+        assert len(set([h1, h2, h3, h4])) == 4     # guaranteed by the algo
+
+    def test_hash_lower_bits(self):
+        self.start_transaction()
+        lp1 = stm_allocate(32)
+        lp2 = stm_allocate(32)
+        lp3 = stm_allocate(32)
+        lp4 = stm_allocate(32)
+        h1 = lib.stm_identityhash(lp1)
+        h2 = lib.stm_identityhash(lp2)
+        h3 = lib.stm_identityhash(lp3)
+        h4 = lib.stm_identityhash(lp4)
+        assert len(set([h1 & 15, h2 & 15, h3 & 15, h4 & 15])) == 4
+
+    def test_hash_around_minor_collect(self):
+        self.start_transaction()
+        lp = stm_allocate(16)
+        h1 = lib.stm_identityhash(lp)
+        self.push_root(lp)
+        stm_minor_collect()
+        lp = self.pop_root()
+        h2 = lib.stm_identityhash(lp)
+        assert h2 == h1
+        assert h2 != lib.stm_id(lp)
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to