[pypy-commit] stmgc default: in-the-middle-of-progress

arigo noreply at buildbot.pypy.org
Fri Jun 14 18:45:02 CEST 2013


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r128:9cfc156e53f7
Date: 2013-06-14 18:44 +0200
http://bitbucket.org/pypy/stmgc/changeset/9cfc156e53f7/

Log:	in-the-middle-of-progress

diff --git a/c4/et.c b/c4/et.c
--- a/c4/et.c
+++ b/c4/et.c
@@ -33,7 +33,7 @@
 static int is_private(gcptr P)
 {
   return (P->h_revision == stm_private_rev_num) ||
-    (P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED);
+            gcflag_private_from_protected(P);
 }
 int _stm_is_private(gcptr P)
 {
@@ -80,7 +80,7 @@
   revision_t v;
 
  restart_all:
-  if (P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED)
+  if (gcflag_private_from_protected(P))
     {
       assert(!(P->h_revision & 1));   /* pointer to the backup copy */
 
@@ -95,14 +95,14 @@
   /* else, for the rest of this function, we can assume that P was not
      a private copy */
 
-  if (P->h_tid & GCFLAG_PUBLIC)
+  if (gcflag_public(P))
     {
       /* follow the chained list of h_revision's as long as they are
          regular pointers.  We will only find more public objects
          along this chain.
       */
     restart_all_public:
-      assert(P->h_tid & GCFLAG_PUBLIC);
+      assert(gcflag_public(P));
       v = ACCESS_ONCE(P->h_revision);
       if (!(v & 1))  // "is a pointer", i.e.
         {            //      "has a more recent revision"
@@ -112,7 +112,7 @@
 
           gcptr P_prev = P;
           P = (gcptr)v;
-          assert(P->h_tid & GCFLAG_PUBLIC);
+          assert(gcflag_public(P));
 
           v = ACCESS_ONCE(P->h_revision);
 
@@ -145,7 +145,7 @@
          because *we* have an entry in d->public_to_private.  (It might
          also be someone else.)
       */
-      if (P->h_tid & GCFLAG_PUBLIC_TO_PRIVATE)
+      if (gcflag_public_to_private(P))
         {
           wlog_t *item;
         retry_public_to_private:;
@@ -154,7 +154,7 @@
           /* We have a key in 'public_to_private'.  The value is the
              corresponding private object. */
           P = item->val;
-          assert(!(P->h_tid & GCFLAG_PUBLIC));
+          assert(!gcflag_public(P));
           assert(is_private(P));
           fprintf(stderr, "read_barrier: %p -> %p public_to_private\n", G, P);
           return P;
@@ -229,7 +229,7 @@
       fprintf(stderr, "read_barrier: %p -> stealing %p...\n  ", G, P);
       stm_steal_stub(P);
 
-      assert(P->h_tid & GCFLAG_PUBLIC);
+      assert(gcflag_public(P));
       goto restart_all_public;
     }
 }
@@ -245,8 +245,8 @@
   if (pubobj == P || ((P->h_revision & 3) == 2 &&
                       pubobj->h_revision == P->h_revision))
     {
-      assert(!(org_pubobj->h_tid & GCFLAG_STUB));
-      assert(!(privobj->h_tid & GCFLAG_PUBLIC));
+      assert(!gcflag_stub(org_pubobj));
+      assert(!gcflag_public(privobj));
       assert(is_private(privobj));
       if (P != org_pubobj)
         fprintf(stderr, "| actually %p ", org_pubobj);
@@ -299,7 +299,7 @@
       return P;
     }
 
-  if (P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED)
+  if (gcflag_private_from_protected(P))
     {
       /* private too, with a backup copy */
       assert(!(P->h_revision & 1));
@@ -307,7 +307,7 @@
       return P;
     }
 
-  if (P->h_tid & GCFLAG_PUBLIC)
+  if (gcflag_public(P))
     {
       fprintf(stderr, "public ");
 
@@ -323,7 +323,7 @@
             }
 
           P = (gcptr)v;
-          assert(P->h_tid & GCFLAG_PUBLIC);
+          assert(gcflag_public(P));
           fprintf(stderr, "-> %p public ", P);
         }
 
@@ -354,12 +354,12 @@
     {
       P = (gcptr)(v - 2);
       fprintf(stderr, "-foreign-> %p ", P);
-      if (P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED)
+      if (gcflag_private_from_protected(P))
         {
           P = (gcptr)P->h_revision;     /* the backup copy */
           fprintf(stderr, "-backup-> %p ", P);
         }
-      if (!(P->h_tid & GCFLAG_PUBLIC))
+      if (!gcflag_public(P))
         {
           fprintf(stderr, "protected by someone else!\n");
           return (gcptr)-1;
@@ -397,10 +397,10 @@
 
   assert(P->h_revision != stm_private_rev_num);
   assert(P->h_revision & 1);
-  assert(!(P->h_tid & GCFLAG_PUBLIC_TO_PRIVATE));
-  assert(!(P->h_tid & GCFLAG_BACKUP_COPY));
-  assert(!(P->h_tid & GCFLAG_STUB));
-  assert(!(P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED));
+  assert(!gcflag_public_to_private(P));
+  assert(!gcflag_backup_copy(P));
+  assert(!gcflag_stub(P));
+  assert(!gcflag_private_from_protected(P));
 
   B = stmgc_duplicate(P);
   B->h_tid |= GCFLAG_BACKUP_COPY;
@@ -410,12 +410,12 @@
 
   gcptrlist_insert(&d->private_from_protected, P);
 
-  return P;
+  return P;   /* always returns its arg: the object is converted in-place */
 }
 
 static gcptr LocalizePublic(struct tx_descriptor *d, gcptr R)
 {
-  assert(R->h_tid & GCFLAG_PUBLIC);
+  assert(gcflag_public(R));
 
 #ifdef _GC_DEBUG
   wlog_t *entry;
@@ -427,9 +427,9 @@
   R->h_tid |= GCFLAG_PUBLIC_TO_PRIVATE;
 
   gcptr L = stmgc_duplicate(R);
-  assert(!(L->h_tid & GCFLAG_BACKUP_COPY));
-  assert(!(L->h_tid & GCFLAG_STUB));
-  assert(!(L->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED));
+  assert(!gcflag_backup_copy(L));
+  assert(!gcflag_stub(L));
+  assert(!gcflag_private_from_protected(L));
   L->h_tid &= ~(GCFLAG_OLD               |
                 GCFLAG_VISITED           |
                 GCFLAG_PUBLIC            |
@@ -439,7 +439,6 @@
                 0);
   L->h_revision = stm_private_rev_num;
   g2l_insert(&d->public_to_private, R, L);
-  gcptrlist_insert(&d->public_to_young, R);
   fprintf(stderr, "write_barrier: adding %p -> %p to public_to_private\n",
           R, L);
 
@@ -450,38 +449,64 @@
   return L;
 }
 
-static inline gcptr check_flag_write_barrier(gcptr W)
+static inline void record_write_barrier(gcptr P)
 {
-  if (W->h_tid & GCFLAG_WRITE_BARRIER)
+  if (gcflag_write_barrier(P))
     {
-      struct tx_descriptor *d = thread_descriptor;
-      gcptrlist_insert(&d->private_old_pointing_to_young, W);
-      W->h_tid &= ~GCFLAG_WRITE_BARRIER;
+      P->h_tid &= ~GCFLAG_WRITE_BARRIER;
+      gcptrlist_insert(&thread_descriptor->old_with_young_pointers_inside, P);
     }
-  return W;
 }
 
 gcptr stm_WriteBarrier(gcptr P)
 {
-  if (P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED)
-    return check_flag_write_barrier(P);
+  if (is_private(P))
+    {
+      /* If we have GCFLAG_WRITE_BARRIER in P, then list it into
+         old_with_young_pointers_inside: it's a private object that may
+         be modified by the program after we return, and the mutation
+         may be to write young pointers (in fact it's a common case).
+      */
+      record_write_barrier(P);
+      return P;
+    }
 
   gcptr R, W;
   R = stm_read_barrier(P);
+
   if (is_private(R))
-    return check_flag_write_barrier(R);
+    {
+      record_write_barrier(P);
+      return P;
+    }
 
   struct tx_descriptor *d = thread_descriptor;
   assert(d->active >= 1);
 
+  /* We need the collection_lock for the sequel; this is required notably
+     because we're about to edit flags on a protected object.
+  */
   spinlock_acquire(d->public_descriptor->collection_lock, 'L');
   if (d->public_descriptor->stolen_objects.size != 0)
     stm_normalize_stolen_objects(d);
 
-  if (R->h_tid & GCFLAG_PUBLIC)
-    W = LocalizePublic(d, R);
+  if (gcflag_public(R))
+    {
+      /* Make and return a new (young) private copy of the public R.
+         Add R into the list 'old_public_with_young_copy'.
+      */
+      assert(gcflag_old(R));
+      gcptrlist_insert(&d->old_public_with_young_copy, R);
+      W = LocalizePublic(d, R);
+    }
   else
-    W = LocalizeProtected(d, R);
+    {
+      /* Turn the protected copy in-place into a private copy.  If it's
+         an old object that still has GCFLAG_WRITE_BARRIER, then we must
+         also record it in the list 'old_with_young_pointers_inside'. */
+      W = LocalizeProtected(d, R);
+      record_write_barrier(W);
+    }
 
   spinlock_release(d->public_descriptor->collection_lock);
 
@@ -528,7 +553,7 @@
       v = ACCESS_ONCE(R->h_revision);
       if (!(v & 1))               // "is a pointer", i.e.
         {                         //   "has a more recent revision"
-          if (R->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED)
+          if (gcflag_private_from_protected(R))
             {
               /* such an object R might be listed in list_of_read_objects
                  before it was turned from protected to private */
@@ -786,7 +811,7 @@
       gcptr R = item->addr;
       revision_t v;
     retry:
-      assert(R->h_tid & GCFLAG_PUBLIC);
+      assert(gcflag_public(R));
       v = ACCESS_ONCE(R->h_revision);
       if (!(v & 1))            // "is a pointer", i.e.
         {                      //   "has a more recent revision"
@@ -806,7 +831,7 @@
         goto retry;
 
       gcptr L = item->val;
-      assert(L->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED ?
+      assert(gcflag_private_from_protected(L) ?
              L->h_revision == (revision_t)R :
              L->h_revision == stm_private_rev_num);
       assert(v != stm_private_rev_num);
@@ -830,7 +855,7 @@
       gcptr L = item->val;
       revision_t expected, v = L->h_revision;
 
-      if (L->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED)
+      if (gcflag_private_from_protected(L))
         expected = (revision_t)R;
       else
         expected = stm_private_rev_num;
@@ -867,10 +892,10 @@
   G2L_LOOP_FORWARD(d->public_to_private, item)
     {
       gcptr L = item->val;
-      assert(!(L->h_tid & GCFLAG_VISITED));
-      assert(!(L->h_tid & GCFLAG_PUBLIC_TO_PRIVATE));
-      assert(!(L->h_tid & GCFLAG_PREBUILT_ORIGINAL));
-      assert(!(L->h_tid & GCFLAG_NURSERY_MOVED));
+      assert(!gcflag_visited(L));
+      assert(!gcflag_public_to_private(L));
+      assert(!gcflag_prebuilt_original(L));
+      assert(!gcflag_nursery_moved(L));
       assert(L->h_revision != localrev);   /* modified by AcquireLocks() */
 
 #ifdef DUMP_EXTRA
@@ -894,9 +919,9 @@
       gcptr R = item->addr;
       revision_t v = (revision_t)item->val;
 
-      assert(R->h_tid & GCFLAG_PUBLIC);
-      assert(R->h_tid & GCFLAG_PUBLIC_TO_PRIVATE);
-      assert(!(R->h_tid & GCFLAG_NURSERY_MOVED));
+      assert(gcflag_public(R));
+      assert(gcflag_public_to_private(R));
+      assert(!gcflag_nursery_moved(R));
       assert(R->h_revision != localrev);
 
 #ifdef DUMP_EXTRA
@@ -907,7 +932,7 @@
       ACCESS_ONCE(R->h_revision) = v;
 
 #if 0
-      if (R->h_tid & GCFLAG_PREBUILT_ORIGINAL)
+      if (gcflag_prebuilt_original(R))
         {
           /* cannot possibly get here more than once for a given value of R */
           pthread_mutex_lock(&mutex_prebuilt_gcroots);
@@ -932,7 +957,7 @@
   for (i = 0; i < size; i++)
     {
       gcptr P = items[i];
-      assert(P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED);
+      assert(gcflag_private_from_protected(P));
       P->h_tid &= ~GCFLAG_PRIVATE_FROM_PROTECTED;
 
       if (P->h_revision & 1)   // "is not a pointer"
@@ -947,7 +972,7 @@
       gcptr B = (gcptr)P->h_revision;
       P->h_revision = new_revision;
 
-      if (B->h_tid & GCFLAG_PUBLIC)
+      if (gcflag_public(B))
         {
           /* B was stolen */
           while (1)
@@ -976,20 +1001,20 @@
   for (i = 0; i < size; i++)
     {
       gcptr P = items[i];
-      assert(P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED);
+      assert(gcflag_private_from_protected(P));
       assert(!(P->h_revision & 1));   // "is a pointer"
 
       gcptr B = (gcptr)P->h_revision;
-      if (B->h_tid & GCFLAG_PUBLIC)
+      if (gcflag_public(B))
         {
-          assert(!(B->h_tid & GCFLAG_BACKUP_COPY));
+          assert(!gcflag_backup_copy(B));
           P->h_tid &= ~GCFLAG_PRIVATE_FROM_PROTECTED;
           P->h_tid |= GCFLAG_PUBLIC;
           /* P becomes a public outdated object */
         }
       else
         {
-          assert(B->h_tid & GCFLAG_BACKUP_COPY);
+          assert(gcflag_backup_copy(B));
           memcpy(P, B, stmcb_size(P));
           P->h_tid &= ~GCFLAG_BACKUP_COPY;
         }
diff --git a/c4/et.h b/c4/et.h
--- a/c4/et.h
+++ b/c4/et.h
@@ -39,11 +39,12 @@
  * GCFLAG_PREBUILT_ORIGINAL is only set on the original version of
  * prebuilt objects.
  *
- * GCFLAG_WRITE_BARRIER is set on *old* objects to track old-to- young
- * pointers.  It may be left set on *public* objects but is ignored
- * there, because public objects are read-only.  The flag is removed
- * once a write occurs and the object is recorded in the list
- * 'old_pointing_to_young'; it is set again at the next minor
+ * GCFLAG_WRITE_BARRIER is set on *old* objects to track old-to-young
+ * pointers.  It is only useful on private objects, and on protected
+ * objects (which may be turned private again).  It may be left set on
+ * public objects but is ignored there, because such objects are read-only.
+ * The flag is removed once a write occurs and the object is recorded in
+ * the list 'old_pointing_to_young'; it is set again at the next minor
  * collection.
  *
  * GCFLAG_NURSERY_MOVED is used temporarily during minor collections.
@@ -82,6 +83,20 @@
                          "PRIVATE_FROM_PROTECTED", \
                          NULL }
 
+#define _DECLARE_FLAG(funcname, flagname)       \
+    static inline _Bool funcname(gcptr P) {     \
+        return (P->h_tid & flagname) != 0; }
+_DECLARE_FLAG(gcflag_old,                    GCFLAG_OLD)
+_DECLARE_FLAG(gcflag_visited,                GCFLAG_VISITED)
+_DECLARE_FLAG(gcflag_public,                 GCFLAG_PUBLIC)
+_DECLARE_FLAG(gcflag_prebuilt_original,      GCFLAG_PREBUILT_ORIGINAL)
+_DECLARE_FLAG(gcflag_public_to_private,      GCFLAG_PUBLIC_TO_PRIVATE)
+_DECLARE_FLAG(gcflag_write_barrier,          GCFLAG_WRITE_BARRIER)
+_DECLARE_FLAG(gcflag_nursery_moved,          GCFLAG_NURSERY_MOVED)
+_DECLARE_FLAG(gcflag_backup_copy,            GCFLAG_BACKUP_COPY)
+_DECLARE_FLAG(gcflag_stub,                   GCFLAG_STUB)
+_DECLARE_FLAG(gcflag_private_from_protected, GCFLAG_PRIVATE_FROM_PROTECTED)
+
 /************************************************************/
 
 #define ABRT_MANUAL               0
diff --git a/c4/nursery.c b/c4/nursery.c
--- a/c4/nursery.c
+++ b/c4/nursery.c
@@ -67,11 +67,11 @@
 
 static inline gcptr create_old_object_copy(gcptr obj)
 {
-    assert(!(obj->h_tid & GCFLAG_NURSERY_MOVED));
-    assert(!(obj->h_tid & GCFLAG_VISITED));
-    assert(!(obj->h_tid & GCFLAG_WRITE_BARRIER));
-    assert(!(obj->h_tid & GCFLAG_PREBUILT_ORIGINAL));
-    assert(!(obj->h_tid & GCFLAG_OLD));
+    assert(!gcflag_nursery_moved(obj));
+    assert(!gcflag_visited(obj));
+    assert(!gcflag_write_barrier(obj));
+    assert(!gcflag_prebuilt_original(obj));
+    assert(!gcflag_old(obj));
 
     size_t size = stmcb_size(obj);
     gcptr fresh_old_copy = stm_malloc(size);
@@ -134,7 +134,7 @@
 
     for (i = 0; i < size; i++) {
         gcptr P = items[i];
-        assert(P->h_tid & GCFLAG_PUBLIC);
+        assert(gcflag_public(P));
 
         revision_t v = ACCESS_ONCE(P->h_revision);
         wlog_t *item;
@@ -145,11 +145,14 @@
                We are in a case where we know the transaction will not
                be able to commit successfully.
             */
+            fprintf(stderr, "public_to_young: %p was modified! abort!\n", P);
             abort();
             AbortTransactionAfterCollect(d, ABRT_COLLECT_MINOR);
             //...
         }
 
+        fprintf(stderr, "public_to_young: %p -> %p in public_to_private\n",
+                item->addr, item->val);
         visit_if_young(&item->val);
         continue;
 
@@ -159,6 +162,7 @@
                It must come from an older transaction that aborted.
                Nothing to do now.
             */
+            fprintf(stderr, "public_to_young: %p ignored\n", P);
             continue;
         }
 
@@ -170,6 +174,8 @@
                in the past, but someone made even more changes.
                Nothing to do now.
             */
+            fprintf(stderr, "public_to_young: %p -> %p not a stub, ignored\n",
+                    P, S);
             continue;
         }
 
@@ -177,6 +183,8 @@
             /* Bah, it's indeed a stub but for another thread.  Nothing
                to do now.
             */
+            fprintf(stderr, "public_to_young: %p -> %p stub wrong thread, "
+                    "ignored\n", P, S);
             continue;
         }
 
@@ -184,6 +192,9 @@
            feet because we hold our own collection_lock.
         */
         gcptr L = (gcptr)(w - 2);
+        fprintf(stderr, "public_to_young: %p -> %p stub -> %p\n",
+                P, S, L);
+
         visit_if_young(&L);
         S->h_revision = ((revision_t)L) | 2;
     }
@@ -203,8 +214,8 @@
     while (gcptrlist_size(&d->old_objects_to_trace) > 0) {
         gcptr obj = gcptrlist_pop(&d->old_objects_to_trace);
 
-        assert(obj->h_tid & GCFLAG_OLD);
-        assert(!(obj->h_tid & GCFLAG_WRITE_BARRIER));
+        assert(gcflag_old(obj));
+        assert(!gcflag_write_barrier(obj));
         obj->h_tid |= GCFLAG_WRITE_BARRIER;
 
         stmcb_trace(obj, &visit_if_young);
diff --git a/c4/nursery.h b/c4/nursery.h
--- a/c4/nursery.h
+++ b/c4/nursery.h
@@ -11,8 +11,8 @@
     char *nursery_end;                                  \
     char *nursery_base;                                 \
     struct GcPtrList old_objects_to_trace;              \
-    struct GcPtrList public_to_young;                   \
-    struct GcPtrList private_old_pointing_to_young;
+    struct GcPtrList old_public_with_young_copy;        \
+    struct GcPtrList old_with_young_pointers_inside;
 
 struct tx_descriptor;  /* from et.h */
 
diff --git a/c4/steal.c b/c4/steal.c
--- a/c4/steal.c
+++ b/c4/steal.c
@@ -55,7 +55,7 @@
 static void replace_ptr_to_protected_with_stub(gcptr *pobj)
 {
     gcptr stub, obj = *pobj;
-    if (obj == NULL || (obj->h_tid & GCFLAG_PUBLIC) != 0)
+    if (obj == NULL || gcflag_public(obj))
         return;
 
     /* we use 'all_stubs', a dictionary, in order to try to avoid
@@ -98,7 +98,7 @@
     /* L might be a private_from_protected, or just a protected copy.
        To know which case it is, read GCFLAG_PRIVATE_FROM_PROTECTED.
     */
-    if (L->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED) {
+    if (gcflag_private_from_protected(L)) {
         gcptr B = (gcptr)L->h_revision;     /* the backup copy */
 
         /* B is now a backup copy, i.e. a protected object, and we own
@@ -107,9 +107,9 @@
         */
         B->h_tid &= ~GCFLAG_BACKUP_COPY;
 
-        if (B->h_tid & GCFLAG_PUBLIC_TO_PRIVATE) {
+        if (gcflag_public_to_private(B)) {
             /* already stolen */
-            assert(B->h_tid & GCFLAG_PUBLIC);
+            assert(gcflag_public(B));
             fprintf(stderr, "already stolen: %p -> %p <-> %p\n", P, L, B);
             L = B;
             goto already_stolen;
@@ -125,7 +125,7 @@
         }
     }
     else {
-        if (L->h_tid & GCFLAG_PUBLIC) {
+        if (gcflag_public(L)) {
             /* already stolen */
             fprintf(stderr, "already stolen: %p -> %p\n", P, L);
             goto already_stolen;
@@ -139,7 +139,7 @@
        thread's collection_lock, so we can read/write the flags.  Change
        it from protected to public.
     */
-    assert(!(L->h_tid & GCFLAG_PUBLIC));
+    assert(!gcflag_public(L));
     L->h_tid |= GCFLAG_PUBLIC;
 
     /* Note that all protected or backup copies have a h_revision that
@@ -192,8 +192,8 @@
         gcptr B = items[i];
         gcptr L = items[i + 1];
 
-        assert(L->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED);
-        assert(!(B->h_tid & GCFLAG_BACKUP_COPY));  /* already removed */
+        assert(gcflag_private_from_protected(L));
+        assert(!gcflag_backup_copy(B));  /* already removed */
 
         g2l_insert(&d->public_to_private, B, L);
 
@@ -218,7 +218,7 @@
         gcptr B = items[i];
         gcptr L = items[i + 1];
 
-        assert(L->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED);
+        assert(gcflag_private_from_protected(L));
         if (B == obj)
             return L;
     }
diff --git a/c4/test/support.py b/c4/test/support.py
--- a/c4/test/support.py
+++ b/c4/test/support.py
@@ -391,18 +391,19 @@
 # ____________________________________________________________
 
 def oalloc(size):
-    "Allocate an 'old' public object, outside any nursery"
+    "Allocate an 'old' protected object, outside any nursery"
     p = ffi.cast("gcptr", lib.stm_malloc(size))
-    p.h_tid = GCFLAG_OLD | GCFLAG_PUBLIC
-    p.h_revision = 1
+    p.h_tid = GCFLAG_OLD | GCFLAG_WRITE_BARRIER
+    p.h_revision = -sys.maxint
     lib.settid(p, 42 + size)
     return p
 
 def oalloc_refs(nrefs):
-    "Allocate an 'old' public object, outside any nursery, with nrefs pointers"
+    """Allocate an 'old' protected object, outside any nursery,
+    with nrefs pointers"""
     p = ffi.cast("gcptr", lib.stm_malloc(HDR + WORD * nrefs))
-    p.h_tid = GCFLAG_OLD | GCFLAG_PUBLIC
-    p.h_revision = 1
+    p.h_tid = GCFLAG_OLD | GCFLAG_WRITE_BARRIER
+    p.h_revision = -sys.maxint
     lib.settid(p, 421 + nrefs)
     for i in range(nrefs):
         rawsetptr(p, i, ffi.NULL)
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
@@ -126,7 +126,7 @@
     check_not_free(p2b)
 
 def test_minor_collection_at_thread_end():
-    p1 = oalloc_refs(1)
+    p1 = palloc_refs(1)
     p2 = nalloc(HDR)
     setptr(p1, 0, p2)
     lib.stm_finalize()
@@ -156,3 +156,31 @@
     check_prebuilt(p0)
     p2 = lib.getptr(p0, 0)
     check_not_free(p2)
+
+def test_old_protected_stay_alive():
+    p0 = oalloc(HDR + WORD)
+    assert classify(p0) == "protected"
+    lib.rawsetlong(p0, 0, 81211)
+    lib.stm_push_root(p0)
+    minor_collect()
+    p0b = lib.stm_pop_root()
+    assert p0b == p0
+    assert classify(p0) == "protected"
+    assert lib.rawgetlong(p0, 0) == 81211
+
+def test_old_private_from_protected_to_young_private():
+    p0 = oalloc_refs(1)
+    assert classify(p0) == "protected"
+    p1 = nalloc(HDR)
+    lib.setptr(p0, 0, p1)
+    assert classify(p0) == "private"   # private_from_protected
+    lib.stm_push_root(p0)
+    minor_collect()
+    p0b = lib.stm_pop_root()
+    assert p0b == p0
+    check_nursery_free(p1)
+    assert classify(p0) == "private"   # private_from_protected
+    p2 = lib.getptr(p0, 0)
+    assert not lib.in_nursery(p2)
+    check_not_free(p2)
+    assert classify(p2) == "private"


More information about the pypy-commit mailing list