Commits

Armin Rigo  committed d2c8017

Trying to remove the hack around hashes. Now taking a hash for the
first time on an object is a write operation, but it simplifies the
(broken) logic.

  • Participants
  • Parent commits b9699de
  • Branches stm-thread-2

Comments (0)

Files changed (7)

File pypy/rpython/lltypesystem/lloperation.py

     # to keep them as operations until the genc stage)
 
     'stm_barrier':            LLOp(sideeffects=False),
+    'stm_read_barrier':       LLOp(),    # explicit read barrier, special case
+    'stm_write_barrier':      LLOp(),    # explicit write barrier, special case
     'stm_become_inevitable':  LLOp(),
     'stm_ptr_eq':             LLOp(sideeffects=False),
     'stm_start_transaction':  LLOp(canrun=True, canmallocgc=True),

File pypy/rpython/memory/gc/stmgc.py

 GCFLAG_LOCAL_COPY        = first_gcflag << 3     # keep in sync with et.h
 GCFLAG_VISITED           = first_gcflag << 4     # keep in sync with et.h
 GCFLAG_HASH_FIELD        = first_gcflag << 5     # keep in sync with et.h
+GCFLAG_NEW_HASH          = first_gcflag << 6     # keep in sync with et.h
 
 GCFLAG_PREBUILT          = GCFLAG_GLOBAL | GCFLAG_NOT_WRITTEN
 REV_INITIAL              = r_uint(1)
-REV_FLAG_NEW_HASH        = r_uint(2)
 
 
 def always_inline(fn):
         return self.identityhash(gcobj)
 
     def identityhash(self, gcobj):
+        gcobj = llop.stm_read_barrier(lltype.typeOf(gcobj), gcobj)
         obj = llmemory.cast_ptr_to_adr(gcobj)
-        obj = self.stm_operations.stm_HashObject(obj)
+        if not (self.header(obj).tid & (GCFLAG_HASH_FIELD | GCFLAG_NEW_HASH)):
+            # 'obj' has no hash so far.  Force one; this is a write operation.
+            localgcobj = llop.stm_write_barrier(lltype.typeOf(gcobj), gcobj)
+            obj = llmemory.cast_ptr_to_adr(localgcobj)
+            self.header(obj).tid |= GCFLAG_NEW_HASH
+        #
         return self._get_object_hash(obj)
 
     def _get_object_hash(self, obj):

File pypy/rpython/memory/gc/stmtls.py

 from pypy.rpython.memory.gc.stmgc import GCFLAG_LOCAL_COPY
 from pypy.rpython.memory.gc.stmgc import GCFLAG_POSSIBLY_OUTDATED
 from pypy.rpython.memory.gc.stmgc import GCFLAG_NOT_WRITTEN
-from pypy.rpython.memory.gc.stmgc import GCFLAG_HASH_FIELD, REV_FLAG_NEW_HASH
+from pypy.rpython.memory.gc.stmgc import GCFLAG_HASH_FIELD, GCFLAG_NEW_HASH
 from pypy.rpython.memory.gc.stmgc import hdr_revision, set_hdr_revision
 
 SIZE_OF_SIGNED = llmemory.sizeof(lltype.Signed)
         size_gc_header = self.gc.gcheaderbuilder.size_gc_header
         totalsize_without_hash = size_gc_header + objsize
         hdr = self.gc.header(obj)
-        has_hash = (hdr.tid & GCFLAG_HASH_FIELD != 0 or
-                    hdr.revision & REV_FLAG_NEW_HASH != 0)
+        has_hash = (hdr.tid & (GCFLAG_HASH_FIELD | GCFLAG_NEW_HASH))
         if has_hash:
             newtotalsize = totalsize_without_hash + (
                 llmemory.sizeof(lltype.Signed))

File pypy/translator/stm/src_stm/et.c

 /************************************************************/
 
 #define ABORT_REASONS 5
-#define SPINLOOP_REASONS 5
+#define SPINLOOP_REASONS 4
 
 struct tx_descriptor {
   jmp_buf *setjmp_buf;
   struct FXCache recent_reads_cache;
 };
 
-static volatile revision_t global_cur_time = 4;        /* always mult of 4 */
+static volatile revision_t global_cur_time = 2;        /* always mult of 2 */
 static volatile revision_t next_locked_value = LOCKED + 3;   /* always odd */
 static __thread struct tx_descriptor *thread_descriptor = NULL;
 
     {
       // no-one else can have changed global_cur_time if I'm inevitable
       cur_time = d->start_time;
-      if (!bool_cas(&global_cur_time, INEVITABLE, cur_time + 4))
+      if (!bool_cas(&global_cur_time, INEVITABLE, cur_time + 2))
         {
           assert(!"global_cur_time modified even though we are inev.");
           abort();
               AcquireLocks(d);
               continue;
             }
-          if (bool_cas(&global_cur_time, cur_time, cur_time + 4))
+          if (bool_cas(&global_cur_time, cur_time, cur_time + 2))
             break;
         }
       // validate (but skip validation if nobody else committed)
   return GlobalizeForComparison(d, P1) == GlobalizeForComparison(d, P2);
 }
 
-gcptr stm_HashObject(gcptr P)
-{
-  /* return one of the objects in the chained list following P out of
-     which the stmgc can determine the hash of P.  The first time we ask
-     for the hash of an object, we set REV_FLAG_NEW_HASH on the last
-     object of the chain.  The hash is then the address of this object.
-     When stm_duplicate further duplicates an object with
-     REV_FLAG_NEW_HASH, it adds an extra field remembering the hash.
-     From then on all stm_duplicates of this object have GCFLAG_HASH_FIELD
-     and the same hash, copied over and over into the extra field. */
-  revision_t v;
-  volatile revision_t *vp;
-
-  if ((P->h_tid & (GCFLAG_GLOBAL|GCFLAG_LOCAL_COPY)) == 0)
-    {
-      // a local object newly created in this transaction
-      P->h_revision |= REV_FLAG_NEW_HASH;
-      return P;
-    }
-
-  while (1)
-    {
-      if (P->h_tid & GCFLAG_HASH_FIELD)
-        {
-          return P;   /* any HASH_FIELD object is fine; we'll read the hash
-                         out of the field. */
-        }
-      vp = (volatile revision_t *)&P->h_revision;
-      v = *vp;
-      if (!(v & 1))  // "is a pointer", i.e. "has a more recent revision"
-        {
-          P = (gcptr)v;    // look into the next one in the chained list
-        }
-      else if (__builtin_expect(v >= LOCKED, 0))
-        {
-          SpinLoop(4);     // spinloop until it is no longer LOCKED, then retry
-        }
-      else if (v & REV_FLAG_NEW_HASH)
-        {
-          return P;        // already has the flag
-        }
-      else
-        {
-          // must add the flag
-          if (bool_cas(vp, v, v | REV_FLAG_NEW_HASH))
-            return P;
-        }
-    }
-}
-
 /************************************************************/
 
 int DescriptorInit(void)

File pypy/translator/stm/src_stm/et.h

   GCFLAG_NOT_WRITTEN       = _first_gcflag << 2,
   GCFLAG_LOCAL_COPY        = _first_gcflag << 3,
   GCFLAG_VISITED           = _first_gcflag << 4,
-  GCFLAG_HASH_FIELD        = _first_gcflag << 5,
 
   GCFLAG_PREBUILT          = GCFLAG_GLOBAL|GCFLAG_NOT_WRITTEN,
   REV_INITIAL              = 1,
-  REV_FLAG_NEW_HASH        = 2,
 };
 
 typedef struct pypy_header0 *gcptr;

File pypy/translator/stm/stmgcintf.py

 
     # for testing
     abort_and_retry  = smexternal('stm_abort_and_retry', [], lltype.Void)
-
-    stm_HashObject = smexternal('stm_HashObject',
-                                [llmemory.Address], llmemory.Address)

File pypy/translator/stm/writebarrier.py

             elif (op.opname in ('ptr_eq', 'ptr_ne') and
                   op.args[0].concretetype.TO._gckind == 'gc'):
                 expand_comparison.add(op)
+            elif op.opname == 'stm_read_barrier':
+                wants_a_barrier[op] = 'R'
+            elif op.opname == 'stm_write_barrier':
+                wants_a_barrier[op] = 'W'
         #
         if wants_a_barrier or expand_comparison:
             # note: 'renamings' maps old vars to new vars, but cast_pointers
             newoperations = []
             for op in block.operations:
                 #
-                if op.opname == 'cast_pointer':
+                opname = op.opname
+                if opname == 'cast_pointer':
                     v = op.args[0]
                     renamings[op.result] = renamings.setdefault(v, [v])
                     continue
                         newoperations.append(newop)
                         v_holder[0] = w
                         category[w] = to
+                    if opname in ('stm_read_barrier', 'stm_write_barrier'):
+                        opname = 'same_as'      # done its job, remove op
                 #
-                newop = SpaceOperation(op.opname,
+                newop = SpaceOperation(opname,
                                        [renamings_get(v) for v in op.args],
                                        op.result)
                 newoperations.append(newop)