[pypy-commit] pypy stm-gc: id() and identityhash().

arigo noreply at buildbot.pypy.org
Fri Feb 10 17:48:00 CET 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: stm-gc
Changeset: r52360:07551dfda0ea
Date: 2012-02-10 17:47 +0100
http://bitbucket.org/pypy/pypy/changeset/07551dfda0ea/

Log:	id() and identityhash().

diff --git a/pypy/rpython/memory/gc/stmgc.py b/pypy/rpython/memory/gc/stmgc.py
--- a/pypy/rpython/memory/gc/stmgc.py
+++ b/pypy/rpython/memory/gc/stmgc.py
@@ -2,6 +2,7 @@
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rpython.lltypesystem.llmemory import raw_malloc_usage
 from pypy.rpython.memory.gc.base import GCBase
+from pypy.rpython.memory.support import mangle_hash
 from pypy.rpython.annlowlevel import llhelper
 from pypy.rlib.rarithmetic import LONG_BIT
 from pypy.rlib.debug import ll_assert, debug_start, debug_stop, fatalerror
@@ -15,7 +16,8 @@
 
 GCFLAG_GLOBAL     = first_gcflag << 0     # keep in sync with et.c
 GCFLAG_WAS_COPIED = first_gcflag << 1     # keep in sync with et.c
-GCFLAG_HAS_HASH   = first_gcflag << 2
+GCFLAG_HAS_SHADOW = first_gcflag << 2
+GCFLAG_FIXED_HASH = first_gcflag << 3
 
 PRIMITIVE_SIZES   = {1: lltype.Char,
                      2: rffi.SHORT,
@@ -45,7 +47,7 @@
     HDR = lltype.Struct('header', ('tid', lltype.Signed),
                                   ('version', llmemory.Address))
     typeid_is_in_field = 'tid'
-    withhash_flag_is_in_field = 'tid', GCFLAG_HAS_HASH
+    withhash_flag_is_in_field = 'tid', GCFLAG_FIXED_HASH
 
     GCTLS = lltype.Struct('GCTLS', ('nursery_free', llmemory.Address),
                                    ('nursery_top', llmemory.Address),
@@ -360,12 +362,63 @@
         ll_thread.release_NOAUTO(lock)
 
     # ----------
+    # id() and identityhash() support
+
+    def id_or_identityhash(self, gcobj, is_hash):
+        """Implement the common logic of id() and identityhash()
+        of an object, given as a GCREF.
+        """
+        obj = llmemory.cast_ptr_to_adr(gcobj)
+        hdr = self.header(obj)
+        #
+        if hdr.tid & GCFLAG_GLOBAL == 0:
+            #
+            # The object is a local object.  Find or allocate a corresponding
+            # global object.
+            if hdr.tid & (GCFLAG_WAS_COPIED | GCFLAG_HAS_SHADOW) == 0:
+                #
+                # We need to allocate a global object here.  We only allocate
+                # it for now; it is left completely uninitialized.
+                size = self.get_size(obj)
+                self.acquire(self.mutex_lock)
+                main_tls = self.main_thread_tls
+                globalobj = self._malloc_local_raw(main_tls, size)
+                self.header(globalobj).tid = GCFLAG_GLOBAL
+                self.release(self.mutex_lock)
+                #
+                # Update the header of the local 'obj'
+                hdr.tid |= GCFLAG_HAS_SHADOW
+                hdr.version = globalobj
+                #
+            else:
+                # There is already a corresponding globalobj
+                globalobj = hdr.version
+            #
+            obj = globalobj
+        #
+        ll_assert(self.header(obj).tid & GCFLAG_GLOBAL != 0,
+                  "id_or_identityhash: unexpected local object")
+        i = llmemory.cast_adr_to_int(obj)
+        if is_hash:
+            # For identityhash(), we need a special case for some
+            # prebuilt objects: their hash must be the same before
+            # and after translation.  It is stored as an extra word
+            # after the object.  But we cannot use it for id()
+            # because the stored value might clash with a real one.
+            if self.header(obj).tid & GCFLAG_FIXED_HASH:
+                size = self.get_size(obj)
+                i = (obj + size).signed[0]
+            else:
+                # mangle the hash value to increase the dispertion
+                # on the trailing bits, but only if !GCFLAG_FIXED_HASH
+                i = mangle_hash(i)
+        return i
 
     def id(self, gcobj):
-        raise NotImplementedError("XXX")
+        return self.id_or_identityhash(gcobj, False)
 
     def identityhash(self, gcobj):
-        raise NotImplementedError("XXX")
+        return self.id_or_identityhash(gcobj, True)
 
 # ------------------------------------------------------------
 
@@ -512,17 +565,31 @@
         ll_assert(hdr.tid & GCFLAG_GLOBAL == 0,
                   "trace_and_mark: GLOBAL obj in nursery")
         #
-        if hdr.tid & GCFLAG_WAS_COPIED != 0:
-            # this local object is a root or was already marked.  Either
-            # way, its 'version' field should point to the corresponding
-            # global object.
-            globalobj = hdr.version
-            #
-        else:
-            # First visit to a local-only 'obj': copy it into the global area
+        if hdr.tid & (GCFLAG_WAS_COPIED | GCFLAG_HAS_SHADOW) == 0:
+            # First visit to a local-only 'obj': allocate a corresponding
+            # global object
             size = self.gc.get_size(obj)
             main_tls = self.gc.main_thread_tls
             globalobj = self.gc._malloc_local_raw(main_tls, size)
+            need_to_copy = True
+            #
+        else:
+            globalobj = hdr.version
+            if hdr.tid & GCFLAG_WAS_COPIED != 0:
+                # this local object is a root or was already marked.  Either
+                # way, its 'version' field should point to the corresponding
+                # global object. 
+                size = 0
+                need_to_copy = False
+            else:
+                # this local object has a shadow made by id_or_identityhash();
+                # and the 'version' field points to the global shadow.
+                ll_assert(hdr.tid & GCFLAG_HAS_SHADOW != 0, "uh?")
+                size = self.gc.get_size(obj)
+                need_to_copy = True
+        #
+        if need_to_copy:
+            # Copy the data of the object from the local to the global
             llmemory.raw_memcopy(obj, globalobj, size)
             #
             # Initialize the header of the 'globalobj'
diff --git a/pypy/rpython/memory/gc/test/test_stmgc.py b/pypy/rpython/memory/gc/test/test_stmgc.py
--- a/pypy/rpython/memory/gc/test/test_stmgc.py
+++ b/pypy/rpython/memory/gc/test/test_stmgc.py
@@ -2,6 +2,7 @@
 from pypy.rpython.lltypesystem import lltype, llmemory, llarena, rffi
 from pypy.rpython.memory.gc.stmgc import StmGC, PRIMITIVE_SIZES, WORD, CALLBACK
 from pypy.rpython.memory.gc.stmgc import GCFLAG_GLOBAL, GCFLAG_WAS_COPIED
+from pypy.rpython.memory.support import mangle_hash
 
 
 S = lltype.GcStruct('S', ('a', lltype.Signed), ('b', lltype.Signed),
@@ -392,3 +393,88 @@
         s1, s1_adr = self.malloc(S)
         assert (repr(self.gc.stm_operations._getsize_fn(s1_adr)) ==
                 repr(fake_get_size(s1_adr)))
+
+    def test_id_of_global(self):
+        s, s_adr = self.malloc(S)
+        i = self.gc.id(s)
+        assert i == llmemory.cast_adr_to_int(s_adr)
+
+    def test_id_of_globallocal(self):
+        s, s_adr = self.malloc(S)
+        self.select_thread(1)
+        t_adr = self.gc.stm_writebarrier(s_adr)   # make a local copy
+        t = llmemory.cast_adr_to_ptr(t_adr, llmemory.GCREF)
+        i = self.gc.id(t)
+        assert i == llmemory.cast_adr_to_int(s_adr)
+        assert i == self.gc.id(s)
+        self.gc.commit_transaction()
+        assert i == self.gc.id(s)
+
+    def test_id_of_local_nonsurviving(self):
+        self.select_thread(1)
+        s, s_adr = self.malloc(S)
+        i = self.gc.id(s)
+        assert i != llmemory.cast_adr_to_int(s_adr)
+        assert i == self.gc.id(s)
+        self.gc.commit_transaction()
+
+    def test_id_of_local_surviving(self):
+        sr1, sr1_adr = self.malloc(SR)
+        self.select_thread(1)
+        t2, t2_adr = self.malloc(S)
+        tr1_adr = self.gc.stm_writebarrier(sr1_adr)
+        assert tr1_adr != sr1_adr
+        tr1 = llmemory.cast_adr_to_ptr(tr1_adr, lltype.Ptr(SR))
+        tr1.s1 = t2
+        i = self.gc.id(t2)
+        assert i not in (llmemory.cast_adr_to_int(sr1_adr),
+                         llmemory.cast_adr_to_int(t2_adr),
+                         llmemory.cast_adr_to_int(tr1_adr))
+        assert i == self.gc.id(t2)
+        self.gc.commit_transaction()
+        s2 = tr1.s1       # tr1 is a root, so not copied yet
+        assert s2 and s2 != t2
+        assert self.gc.id(s2) == i
+
+    def test_hash_of_global(self):
+        s, s_adr = self.malloc(S)
+        i = self.gc.identityhash(s)
+        assert i == mangle_hash(llmemory.cast_adr_to_int(s_adr))
+
+    def test_hash_of_globallocal(self):
+        s, s_adr = self.malloc(S)
+        self.select_thread(1)
+        t_adr = self.gc.stm_writebarrier(s_adr)   # make a local copy
+        t = llmemory.cast_adr_to_ptr(t_adr, llmemory.GCREF)
+        i = self.gc.identityhash(t)
+        assert i == mangle_hash(llmemory.cast_adr_to_int(s_adr))
+        assert i == self.gc.identityhash(s)
+        self.gc.commit_transaction()
+        assert i == self.gc.identityhash(s)
+
+    def test_hash_of_local_nonsurviving(self):
+        self.select_thread(1)
+        s, s_adr = self.malloc(S)
+        i = self.gc.identityhash(s)
+        assert i != mangle_hash(llmemory.cast_adr_to_int(s_adr))
+        assert i == self.gc.identityhash(s)
+        self.gc.commit_transaction()
+
+    def test_hash_of_local_surviving(self):
+        sr1, sr1_adr = self.malloc(SR)
+        self.select_thread(1)
+        t2, t2_adr = self.malloc(S)
+        tr1_adr = self.gc.stm_writebarrier(sr1_adr)
+        assert tr1_adr != sr1_adr
+        tr1 = llmemory.cast_adr_to_ptr(tr1_adr, lltype.Ptr(SR))
+        tr1.s1 = t2
+        i = self.gc.identityhash(t2)
+        assert i not in map(mangle_hash,
+                        (llmemory.cast_adr_to_int(sr1_adr),
+                         llmemory.cast_adr_to_int(t2_adr),
+                         llmemory.cast_adr_to_int(tr1_adr)))
+        assert i == self.gc.identityhash(t2)
+        self.gc.commit_transaction()
+        s2 = tr1.s1       # tr1 is a root, so not copied yet
+        assert s2 and s2 != t2
+        assert self.gc.identityhash(s2) == i


More information about the pypy-commit mailing list