Commits

Remi Meier committed b89b61f

document the real reason why we can't use just any h_original and
prevent things like stub->stub->stub on public addresses.

Comments (0)

Files changed (7)

 - prebuilt object, never modified                          1
 - other public object, never modified                     GT
 - outdated                             ptr to a more recent public copy
+- stolen protected, made public                        some PRN
 
 Public stubs (have also a ref to one thread):
 - from stealing                            ptr (maybe to priv/prot) | 2
 it is a predefined HASH value for this object. This is used by
 `stm_hash` which otherwise returns a hashed version of the ID of
 the object.
+
+DONT ASSUME THE H_ORIGINAL TO BE INITIALIZED. IT MAY HAVE E.G.
+H_REVISION SET TO AN OLD, FREED OBJECT.
               if (v & 2)
                 goto follow_stub;
 
-              /* we update P_prev->h_revision as a shortcut */
+              /* we update P_prev->h_revision as a shortcut
+                 P_prev->P->v  =>  P_prev->v */
               /* XXX check if this really gives a worse performance than only
                  doing this write occasionally based on a counter in d */
               P_prev->h_revision = v;
   B = stmgc_duplicate_old(P);
   B->h_tid |= GCFLAG_BACKUP_COPY;
   B->h_tid &= ~GCFLAG_HAS_ID;
+
   if (!(P->h_original) && (P->h_tid & GCFLAG_OLD)) {
     /* if P is old, it must be the original
        if P is young, it will create a shadow original later
     }
     assert(obj->h_tid & GCFLAG_OLD);
 
+    if (stm_is_registered(obj)) {
+        /* prevents stub->stub->stub->... */
+        /* only increment refcount: */
+        stm_register_integer_address((intptr_t)obj);
+        return (intptr_t)obj;
+    }
+
     spinlock_acquire(d->public_descriptor->collection_lock, 'P');
 
     /* it must have a h_original */
     gcptr orig;
-    if (obj->h_original == 0 || obj->h_tid & GCFLAG_PREBUILT_ORIGINAL) {
+    if ((!obj->h_original) || (obj->h_tid & GCFLAG_PREBUILT_ORIGINAL)) {
         orig = obj;
     } else {
         orig = (gcptr)obj->h_original;
     }
     
-    if ((orig->h_tid & (GCFLAG_PUBLIC | GCFLAG_PREBUILT_ORIGINAL))
-        == (GCFLAG_PUBLIC | GCFLAG_PREBUILT_ORIGINAL)) {
-        /* public is not enough as public stubs may get replaced
-           by the protected object they point to, if they are in the 
-           same thread (I think...) */
+    if ((orig->h_tid & GCFLAG_PUBLIC) 
+        && (obj->h_tid & GCFLAG_PREBUILT_ORIGINAL)) {
+        /* we can't just use *any* public original because their
+           h_revision is not kept up-to-date during major collections.
+           Meaning it can point to some long gone object.
+           Prebuilt originals, however, always get visited in major
+           collections. */
         result = (intptr_t)orig;
     }
     else {
         /* must create shadow original object XXX: or use
            backup, if exists */
         gcptr O = (gcptr)stmgcpage_malloc(stmgc_size(p));
-        memcpy(O, p, stmgc_size(p)); /* at least major collections
-                                      depend on some content of id_copy.
-                                      remove after fixing that XXX */
+        memcpy(O, p, sizeof(struct stm_object_s));
+
         O->h_tid |= GCFLAG_OLD;
+        assert(O->h_original == 0);
+        assert(O->h_revision = -1);     /* debugging */
 
         p->h_original = (revision_t)O;
         p->h_tid |= GCFLAG_HAS_ID;
             gcptr B = (gcptr)p->h_revision;
             /* not stolen already: */
             assert(!(B->h_tid & GCFLAG_PUBLIC));
+            assert(!B->h_original);
             B->h_original = (revision_t)O;
         }
         
     }
 }
 
+static void check_consistent(gcptr obj) {
+    if ((obj->h_revision & 3) == 2)
+        assert(stm_pointer_equal(obj, (gcptr)(obj->h_revision-2)));
+    else if ((obj->h_revision & 1) == 0)
+        assert(stm_pointer_equal(obj, (gcptr)(obj->h_revision)));
+}
+
 
 /***** Support code *****/
 
 
 /***** registering of small stubs as integer addresses *****/
 
+_Bool stm_is_registered(gcptr obj)
+{
+    wlog_t *found;
+    _Bool res = 0;
+
+    stmgcpage_acquire_global_lock();
+    /* find and increment refcount; or insert */
+    G2L_FIND(registered_objs, obj, found, goto finish);
+    found->val = (gcptr)(((revision_t)found->val) + 1);
+    goto finish;
+    res = 1;
+ finish:
+    stmgcpage_release_global_lock();
+    return res;
+}
+
 void stm_register_integer_address(intptr_t adr)
 {                               /* needs to be inevitable! */
     wlog_t *found;
     /* become inevitable because we would have to re-register them
        on abort, but make sure only to re-register if not registered
        in the same aborted transaction (XXX) */
+    /* (obj will not move) */
     stm_become_inevitable("stm_unregister_integer_address()");
 
     stmgcpage_acquire_global_lock();
 
 static gcptr copy_over_original(gcptr obj, gcptr id_copy)
 {
+    /* no obj->h_revision = obj->h_original = id_copy */
+    assert(!((obj->h_revision <= ((revision_t)id_copy + 2)) && 
+             (obj->h_revision >= ((revision_t)id_copy))));
+
     assert(obj != id_copy);
     assert(id_copy == (gcptr)obj->h_original);
     assert(!(id_copy->h_revision & 1)); /* not head-revision itself */
                    == (GCFLAG_MARKED|GCFLAG_VISITED|GCFLAG_PUBLIC));
             continue;
         }
-        /* else if (R->h_original == 0) { */
-        /*     /\* the obj is an original and will therefore survive: *\/ */
-        /*     gcptr V = visit_public(R, NULL); */
-        /*     assert(V == R); */
-        /* } */
         else {
             assert(R->h_tid & GCFLAG_SMALLSTUB); /* only case for now */
             /* make sure R stays valid: */
 
             /* priv_from_prot's backup->h_originals already point
                to id_obj */
+            assert(IMPLIES(obj->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED,
+                           ((gcptr)obj->h_revision)->h_original
+                           == obj->h_original));
         } 
         else {
             /* make a copy of it outside */
         obj->h_original = (revision_t)stub; 
         stub->h_original = 0;   /* stub_malloc does not set to 0... */
         if (obj->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED) {
+            assert(!(((gcptr)obj->h_revision)->h_original));
             ((gcptr)obj->h_revision)->h_original = (revision_t)stub;
         }
     }
    called on the result (push roots!) */
 intptr_t stm_allocate_public_integer_address(gcptr);
 void stm_unregister_integer_address(intptr_t); /* push roots too! */
-
+_Bool stm_is_registered(gcptr);
 
 /* returns a never changing hash for the object */
 revision_t stm_hash(gcptr);