Author: Armin Rigo <ar...@tunes.org>
Branch: stm-thread-2
Changeset: r57203:f23da2c9b5f4
Date: 2012-09-07 10:01 +0200
http://bitbucket.org/pypy/pypy/changeset/f23da2c9b5f4/

Log:    Fix 'stmgc': in-progress

diff --git a/pypy/annotation/model.py b/pypy/annotation/model.py
--- a/pypy/annotation/model.py
+++ b/pypy/annotation/model.py
@@ -203,7 +203,6 @@
 class SomeInteger(SomeFloat):
     "Stands for an object which is known to be an integer."
     knowntype = int
-    # size is in multiples of C's sizeof(long)!
     def __init__(self, nonneg=False, unsigned=None, knowntype=None):
         assert (knowntype is None or knowntype is int or
                 issubclass(knowntype, base_int))
diff --git a/pypy/rpython/lltypesystem/llmemory.py 
b/pypy/rpython/lltypesystem/llmemory.py
--- a/pypy/rpython/lltypesystem/llmemory.py
+++ b/pypy/rpython/lltypesystem/llmemory.py
@@ -515,6 +515,13 @@
         else:
             return 0
 
+    def _cast_to_uint(self, symbolic=False):
+        if self:
+            assert not isinstance(self.ptr._obj0, int)
+            return AddressAsUInt(self)
+        else:
+            return r_uint(0)
+
     def _fixup(self):
         if self.ptr is not None and self.ptr._was_freed():
             # hack to support llarena.test_replace_object_with_stub()
@@ -549,10 +556,18 @@
             return AddressAsInt(cast_ptr_to_adr(fieldadr))
         return NotImplemented
     def __repr__(self):
+        clsname = self.__class__.__name__
         try:
-            return '<AddressAsInt %s>' % (self.adr.ptr,)
+            return '<%s %s>' % (clsname, self.adr.ptr)
         except AttributeError:
-            return '<AddressAsInt at 0x%x>' % (uid(self),)
+            return '<%s at 0x%x>' % (clsname, uid(self))
+
+class AddressAsUInt(AddressAsInt):
+    def annotation(self):
+        from pypy.annotation import model
+        return model.SomeInteger(unsigned=True)
+    def lltype(self):
+        return lltype.Unsigned
 
 # ____________________________________________________________
 
@@ -678,6 +693,9 @@
         res = cast(lltype.Signed, res)
     return res
 
+def cast_adr_to_uint_symbolic(adr):
+    return adr._cast_to_uint()
+
 _NONGCREF = lltype.Ptr(lltype.OpaqueType('NONGCREF'))
 def cast_int_to_adr(int):
     if isinstance(int, AddressAsInt):
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
@@ -119,8 +119,9 @@
 GCFLAG_POSSIBLY_OUTDATED = first_gcflag << 1     # keep in sync with et.h
 GCFLAG_NOT_WRITTEN       = first_gcflag << 2     # keep in sync with et.h
 GCFLAG_LOCAL_COPY        = first_gcflag << 3     # keep in sync with et.h
-GCFLAG_HAS_SHADOW        = first_gcflag << 4
-GCFLAG_FIXED_HASH        = first_gcflag << 5
+GCFLAG_VISITED           = first_gcflag << 4
+GCFLAG_HAS_SHADOW        = first_gcflag << 5
+GCFLAG_FIXED_HASH        = first_gcflag << 6
 
 
 def always_inline(fn):
@@ -188,8 +189,8 @@
         # The following line causes the _stm_getsize() function to be
         # generated in the C source with a specific signature, where it
         # can be called by the C code.
-        llop.nop(lltype.Void, llhelper(self.stm_operations.GETSIZE,
-                                       self._stm_getsize))
+        llop.nop(lltype.Void, llhelper(self.stm_operations.DUPLICATE,
+                                       self._stm_duplicate))
         #
         self.sharedarea.setup()
         #
@@ -278,7 +279,7 @@
     def collect(self, gen=1):
         self.get_tls().local_collection()
         if gen > 0:
-            debug_print("XXX not doing a global collect()")
+            debug_print("XXX not implemented: global collect()")
 
     def start_transaction(self):
         self.get_tls().start_transaction()
@@ -305,6 +306,12 @@
         flags |= GCFLAG_GLOBAL
         self.init_gc_object(addr, typeid16, flags)
 
+    def obj_revision(obj):
+        return hdr_revision(self.header(obj))
+
+    def set_obj_revision(obj, nrevision):
+        set_hdr_revision(self.header(obj), nrevision)
+
     def stm_duplicate(self, obj):
         size_gc_header = self.gcheaderbuilder.size_gc_header
         size = self.get_size(obj)
@@ -357,11 +364,11 @@
                 #
                 # Update the header of the local 'obj'
                 hdr.tid |= GCFLAG_HAS_SHADOW
-                hdr.version = fixedobj
+                set_hdr_revision(hdr, fixedobj)
                 #
             else:
                 # There is already a corresponding fixedobj
-                fixedobj = hdr.version
+                fixedobj = hdr_revision(hdr)
             #
             obj = fixedobj
             #
@@ -391,3 +398,13 @@
 
     def identityhash(self, gcobj):
         return self.id_or_identityhash(gcobj, True)
+
+
+# ____________________________________________________________
+# helpers
+
+def hdr_revision(hdr):
+    return llmemory.cast_int_to_adr(hdr.revision)
+
+def set_hdr_revision(hdr, nrevision):
+    hdr.revision = llmemory.cast_adr_to_uint_symbolic(nrevision)
diff --git a/pypy/rpython/memory/gc/stmshared.py 
b/pypy/rpython/memory/gc/stmshared.py
--- a/pypy/rpython/memory/gc/stmshared.py
+++ b/pypy/rpython/memory/gc/stmshared.py
@@ -52,5 +52,9 @@
             self.free_object(obj)
             obj = next
 
+    def free_and_clear_list(self, lst):
+        while lst.non_empty():
+            self.free_object(lst.pop())
+
     def delete(self):
         free_non_gc_object(self)
diff --git a/pypy/rpython/memory/gc/stmtls.py b/pypy/rpython/memory/gc/stmtls.py
--- a/pypy/rpython/memory/gc/stmtls.py
+++ b/pypy/rpython/memory/gc/stmtls.py
@@ -10,7 +10,9 @@
 from pypy.rpython.memory.gc.stmgc import WORD, NULL
 from pypy.rpython.memory.gc.stmgc import always_inline, dont_inline
 from pypy.rpython.memory.gc.stmgc import GCFLAG_GLOBAL, GCFLAG_VISITED
-from pypy.rpython.memory.gc.stmgc import GCFLAG_WAS_COPIED, GCFLAG_HAS_SHADOW
+from pypy.rpython.memory.gc.stmgc import GCFLAG_LOCAL_COPY, GCFLAG_HAS_SHADOW
+from pypy.rpython.memory.gc.stmgc import GCFLAG_POSSIBLY_OUTDATED
+from pypy.rpython.memory.gc.stmgc import hdr_revision
 
 
 class StmGCTLS(object):
@@ -41,7 +43,9 @@
         # --- a thread-local allocator for the shared area
         from pypy.rpython.memory.gc.stmshared import StmGCThreadLocalAllocator
         self.sharedarea_tls = StmGCThreadLocalAllocator(self.gc.sharedarea)
-        # --- the LOCAL objects with GCFLAG_WAS_COPIED
+        # --- the GCFLAG_LOCAL_COPY objects are also allocated with
+        #     self.sharedarea_tls, but we need their 'revision', so we
+        #     can't do add_regular() on them.  They go here instead:
         self.copied_local_objects = self.AddressStack()
         # --- the LOCAL objects which are weakrefs.  They are also listed
         #     in the appropriate place, like sharedarea_tls, if needed.
@@ -122,7 +126,7 @@
         # malloced objects will be LOCAL.
         if self.gc.DEBUG:
             self.check_all_global_objects()
-        self.relocalize_from_stack()
+        #self.relocalize_from_stack()
 
     def stop_transaction(self):
         """Stop a transaction: do a local collection to empty the
@@ -157,9 +161,9 @@
         debug_start("gc-local")
         #
         if end_of_transaction:
-            self.detect_flag_combination = GCFLAG_WAS_COPIED | GCFLAG_VISITED
+            self.replace_pointers_following_revision = GCFLAG_LOCAL_COPY
         else:
-            self.detect_flag_combination = -1
+            self.replace_pointers_following_revision = 0
         #
         # Move away the previous sharedarea_tls and start a new one.
         from pypy.rpython.memory.gc.stmshared import StmGCThreadLocalAllocator
@@ -251,6 +255,7 @@
         return localobj
 
     def fresh_new_weakref(self, obj):
+        XXX  # review
         self.local_weakrefs.append(obj)
 
     # ------------------------------------------------------------
@@ -258,7 +263,8 @@
     def _promote_locals_to_globals(self):
         ll_assert(self.local_nursery_is_empty(), "nursery must be empty [1]")
         #
-        # Promote all objects in sharedarea_tls to global
+        # Promote all objects in sharedarea_tls to global.
+        # This is the "real" equivalent of _FakeReach() in et.c.
         obj = self.sharedarea_tls.chained_list
         self.sharedarea_tls.chained_list = NULL
         #
@@ -267,18 +273,19 @@
             obj = hdr.version
             ll_assert(hdr.tid & GCFLAG_GLOBAL == 0, "already GLOBAL [1]")
             ll_assert(hdr.tid & GCFLAG_VISITED == 0, "unexpected VISITED [1]")
-            hdr.tid |= GCFLAG_GLOBAL
-            self._clear_version_for_global_object(hdr)
+            hdr.tid |= GCFLAG_GLOBAL | GCFLAG_NOT_WRITTEN
+            if hdr.tid & GCFLAG_LOCAL_COPY == 0:
+                self._clear_version_for_global_object(hdr)
 
     def _clear_version_for_global_object(self, hdr):
         # Reset the 'version' to initialize a newly global object.
-        # When translated with C code, we set it to NULL (version 0).
+        # When translated with C code, we set it to 1.
         # When non-translated, we reset it instead to '_uninitialized'
         # to simulate the fact that the C code might change it.
         if we_are_translated():
-            hdr.version = NULL
+            hdr.revision = r_uint(1)
         else:
-            del hdr.version
+            del hdr.revision
 
     def _cleanup_state(self):
         #if self.rawmalloced_objects:
@@ -287,57 +294,50 @@
         # free the old unused local objects still allocated in the
         # StmGCThreadLocalAllocator
         self.sharedarea_tls.free_and_clear()
-        # free the local copies.  Note that commonly, they are leftovers
-        # from the previous transaction running in this thread.  The C code
-        # has just copied them over the corresponding GLOBAL objects at the
-        # very end of that transaction.
-        self._free_and_clear_list(self.copied_local_objects)
+        # free these ones too
+        self.sharedarea_tls.free_and_clear_list(self.copied_local_objects)
         # forget the local weakrefs.
         self.local_weakrefs.clear()
 
-    def _free_and_clear_list(self, lst):
-        while lst.non_empty():
-            self.sharedarea_tls.free_object(lst.pop())
-
 
     def collect_roots_from_stack(self, end_of_transaction):
-        if end_of_transaction:
-            # in this mode, we flag the reference to local objects in order
-            # to re-localize them when we later start the next transaction
-            # using this section of the shadowstack
-            self.gc.root_walker.walk_current_stack_roots(
-                StmGCTLS._trace_drag_out_and_flag_local, self)
-        else:
+##        if end_of_transaction:
+##            # in this mode, we flag the reference to local objects in order
+##            # to re-localize them when we later start the next transaction
+##            # using this section of the shadowstack
+##            self.gc.root_walker.walk_current_stack_roots(
+##                StmGCTLS._trace_drag_out_and_flag_local, self)
+##        else:
             self.gc.root_walker.walk_current_stack_roots(
                 StmGCTLS._trace_drag_out1, self)
 
-    def _trace_drag_out_and_flag_local(self, root):
-        x = llmemory.cast_adr_to_int(root.address[0])
-        if x & 2:
-            root.address[0] -= 2
-        old_tid = self.gc.header(root.address[0]).tid
-        #
-        self._trace_drag_out1(root)
-        #
-        # if root.address[0] used to point to a local object, then flag
-        # this by adding the bit of value 2.
-        if old_tid & GCFLAG_GLOBAL == 0:
-            obj = root.address[0]
-            x = llmemory.cast_adr_to_int(obj)
-            ll_assert(x & 3 == 0, "flag_local: misaligned obj")
-            obj = llarena.getfakearenaaddress(obj)
-            root.address[0] = obj + 2
+##    def _trace_drag_out_and_flag_local(self, root):
+##        x = llmemory.cast_adr_to_int(root.address[0])
+##        if x & 2:
+##            root.address[0] -= 2
+##        old_tid = self.gc.header(root.address[0]).tid
+##        #
+##        self._trace_drag_out1(root)
+##        #
+##        # if root.address[0] used to point to a local object, then flag
+##        # this by adding the bit of value 2.
+##        if old_tid & GCFLAG_GLOBAL == 0:
+##            obj = root.address[0]
+##            x = llmemory.cast_adr_to_int(obj)
+##            ll_assert(x & 3 == 0, "flag_local: misaligned obj")
+##            obj = llarena.getfakearenaaddress(obj)
+##            root.address[0] = obj + 2
 
-    def relocalize_from_stack(self):
-        self.gc.root_walker.walk_current_stack_roots(
-            StmGCTLS._relocalize_from_stack, self)
+##    def relocalize_from_stack(self):
+##        self.gc.root_walker.walk_current_stack_roots(
+##            StmGCTLS._relocalize_from_stack, self)
 
-    def _relocalize_from_stack(self, root):
-        x = llmemory.cast_adr_to_int(root.address[0])
-        if x & 2:
-            obj = root.address[0] - 2
-            localobj = self.gc.stm_writebarrier(obj)
-            root.address[0] = localobj
+##    def _relocalize_from_stack(self, root):
+##        x = llmemory.cast_adr_to_int(root.address[0])
+##        if x & 2:
+##            obj = root.address[0] - 2
+##            localobj = self.gc.stm_writebarrier(obj)
+##            root.address[0] = localobj
 
     def collect_from_raw_structures(self):
         self.gc.root_walker.walk_current_nongc_roots(
@@ -360,19 +360,19 @@
         """Return the current surviving state of the object:
             0: not marked as surviving, so far
             1: survives and does not move
-            2: survives, but moves to 'hdr.version'
+            2: survives, but moves to 'hdr.revision'
         """
         hdr = self.gc.header(obj)
         flag_combination = hdr.tid & (GCFLAG_GLOBAL |
-                                      GCFLAG_WAS_COPIED |
+                                      GCFLAG_LOCAL_COPY |
                                       GCFLAG_VISITED)
         if flag_combination == 0:
             return 0    # not marked as surviving, so far
 
-        if flag_combination == self.detect_flag_combination:
-            # At a normal time, self.detect_flag_combination is -1
-            # and this case is never seen.  At end of transactions,
-            # detect_flag_combination is GCFLAG_WAS_COPIED|GCFLAG_VISITED.
+        if flag_combination & self.replace_pointers_following_revision:
+            # At a normal time, self.replace_pointers_following_revision
+            # is 0 and this case is never seen.  At end of transactions,
+            # detect_flag_combination is GCFLAG_LOCAL_COPY.
             # This case is to force pointers to the LOCAL copy to be
             # replaced with pointers to the GLOBAL copy.
             return 2
@@ -484,19 +484,19 @@
     def _stm_enum_callback(tlsaddr, globalobj, localobj):
         self = StmGCTLS.cast_address_to_tls_object(tlsaddr)
         localhdr = self.gc.header(localobj)
-        ll_assert(localhdr.version == globalobj,
+        ll_assert(hdr_revision(localhdr) == globalobj,
                   "in a root: localobj.version != globalobj")
         ll_assert(localhdr.tid & GCFLAG_GLOBAL == 0,
                   "in a root: unexpected GCFLAG_GLOBAL")
-        ll_assert(localhdr.tid & GCFLAG_WAS_COPIED != 0,
-                  "in a root: missing GCFLAG_WAS_COPIED")
-        ll_assert(localhdr.tid & GCFLAG_VISITED != 0,
-                  "in a root: missing GCFLAG_VISITED")
+        ll_assert(localhdr.tid & GCFLAG_LOCAL_COPY != 0,
+                  "in a root: missing GCFLAG_LOCAL_COPY")
+        ll_assert(localhdr.tid & GCFLAG_VISITED == 0,
+                  "in a root: unexpected GCFLAG_VISITED")
         globalhdr = self.gc.header(globalobj)
         ll_assert(globalhdr.tid & GCFLAG_GLOBAL != 0,
                   "in a root: GLOBAL: missing GCFLAG_GLOBAL")
-        ll_assert(globalhdr.tid & GCFLAG_WAS_COPIED != 0,
-                  "in a root: GLOBAL: missing GCFLAG_WAS_COPIED")
+        ll_assert(globalhdr.tid & GCFLAG_POSSIBLY_OUTDATED != 0,
+                  "in a root: GLOBAL: missing GCFLAG_POSSIBLY_OUTDATED")
         ll_assert(globalhdr.tid & GCFLAG_VISITED == 0,
                   "in a root: GLOBAL: unexpected GCFLAG_VISITED")
         TL = lltype.cast_primitive(lltype.Signed,
@@ -505,7 +505,8 @@
                                    self.gc.get_type_id(globalobj))
         ll_assert(TL == TG, "in a root: type(LOCAL) != type(GLOBAL)")
         #
-        self.trace_and_drag_out_of_nursery(localobj)
+        localhdr.tid |= GCFLAG_VISITED
+        self.pending.append(localobj)
 
     def collect_flush_pending(self):
         # Follow the objects in the 'pending' stack and move the
@@ -566,8 +567,8 @@
 
     def _debug_check_all_global_from_stack_1(self, root):
         obj = root.address[0]
-        if llmemory.cast_adr_to_int(obj) & 2:
-            obj -= 2     # will be fixed by relocalize_from_stack()
+##        if llmemory.cast_adr_to_int(obj) & 2:
+##            obj -= 2     # will be fixed by relocalize_from_stack()
         self._debug_check_all_global_obj(obj)
 
     def _debug_check_all_global(self, root, ignored):
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
@@ -1,8 +1,10 @@
 import py
 from pypy.rpython.lltypesystem import lltype, llmemory, llarena, llgroup, rffi
 from pypy.rpython.memory.gc.stmgc import StmGC, WORD
-from pypy.rpython.memory.gc.stmgc import GCFLAG_GLOBAL, GCFLAG_WAS_COPIED
-from pypy.rpython.memory.gc.stmgc import GCFLAG_VISITED
+from pypy.rpython.memory.gc.stmgc import GCFLAG_GLOBAL, GCFLAG_NOT_WRITTEN
+from pypy.rpython.memory.gc.stmgc import GCFLAG_POSSIBLY_OUTDATED
+from pypy.rpython.memory.gc.stmgc import GCFLAG_LOCAL_COPY
+from pypy.rpython.memory.gc.stmgc import hdr_revision, set_hdr_revision
 from pypy.rpython.memory.support import mangle_hash
 
 
@@ -86,20 +88,20 @@
         for key, value in self._tldicts[self.threadnum].iteritems():
             callback(tls, key, value)
 
-    def read_attribute(self, obj, name):
-        obj = llmemory.cast_ptr_to_adr(obj)
-        hdr = self._gc.header(obj)
-        localobj = self.tldict_lookup(obj)
-        if localobj == llmemory.NULL:
-            localobj = obj
-        else:
-            assert hdr.tid & GCFLAG_GLOBAL != 0
-        localobj = llmemory.cast_adr_to_ptr(localobj, lltype.Ptr(SR))
-        return getattr(localobj, name)
+##    def read_attribute(self, obj, name):
+##        obj = llmemory.cast_ptr_to_adr(obj)
+##        hdr = self._gc.header(obj)
+##        localobj = self.tldict_lookup(obj)
+##        if localobj == llmemory.NULL:
+##            localobj = obj
+##        else:
+##            assert hdr.tid & GCFLAG_GLOBAL != 0
+##        localobj = llmemory.cast_adr_to_ptr(localobj, lltype.Ptr(SR))
+##        return getattr(localobj, name)
 
-    def stm_copy_transactional_to_raw(self, srcobj, dstobj, size):
-        llmemory.raw_memcopy(srcobj, dstobj, size)
-        self._transactional_copies.append((srcobj, dstobj))
+##    def stm_copy_transactional_to_raw(self, srcobj, dstobj, size):
+##        llmemory.raw_memcopy(srcobj, dstobj, size)
+##        self._transactional_copies.append((srcobj, dstobj))
 
 
 def fake_get_size(obj):
@@ -179,7 +181,8 @@
                                         1)
             llarena.arena_reserve(adr1, totalsize)
             addr = adr1 + self.gc.gcheaderbuilder.size_gc_header
-            self.gc.header(addr).tid = self.gc.combine(tid, GCFLAG_GLOBAL)
+            self.gc.header(addr).tid = self.gc.combine(
+                tid, GCFLAG_GLOBAL | GCFLAG_NOT_WRITTEN)
             realobj = llmemory.cast_adr_to_ptr(addr, lltype.Ptr(STRUCT))
         else:
             gcref = self.gc.malloc_fixedsize_clear(tid, size,
@@ -205,9 +208,27 @@
             assert (hdr.tid & GCFLAG_WAS_COPIED != 0) == must_have_was_copied
         if must_have_version != '?':
             assert hdr.version == must_have_version
-    def read_signed(self, obj, offset):
-        meth = getattr(self.gc, 'read_int%d' % WORD)
-        return meth(obj, offset)
+
+    def stm_writebarrier(self, P):
+        if lltype.typeOf(P) != llmemory.Address:
+            P = llmemory.cast_ptr_to_adr(P)
+        hdr = self.gc.header(P)
+        if hdr.tid & GCFLAG_NOT_WRITTEN == 0:
+            # already a local, written-to object
+            assert hdr.tid & GCFLAG_GLOBAL == 0
+            assert hdr.tid & GCFLAG_POSSIBLY_OUTDATED == 0
+            W = P
+        else:
+            # slow case of the write barrier
+            if hdr.tid & GCFLAG_GLOBAL == 0:
+                W = P
+                R = hdr_revision(hdr)
+            else:
+                R = P
+                W = self.gc.stm_operations.tldict_lookup(R)
+            self.gc.header(W).tid &= ~GCFLAG_NOT_WRITTEN
+            self.gc.header(R).tid |= GCFLAG_POSSIBLY_OUTDATED
+        return W
 
 
 class TestBasic(StmGCTests):
@@ -246,18 +267,20 @@
     def test_write_barrier_exists(self):
         self.select_thread(1)
         t, t_adr = self.malloc(S)
-        obj = self.gc.stm_writebarrier(t_adr)     # local object
+        obj = self.stm_writebarrier(t_adr)     # local object
         assert obj == t_adr
         #
         self.select_thread(0)
         s, s_adr = self.malloc(S)
         #
         self.select_thread(1)
-        self.gc.header(s_adr).tid |= GCFLAG_WAS_COPIED
-        self.gc.header(t_adr).tid |= GCFLAG_WAS_COPIED | GCFLAG_VISITED
-        self.gc.header(t_adr).version = s_adr
+        assert self.gc.header(s_adr).tid & GCFLAG_GLOBAL != 0
+        assert self.gc.header(t_adr).tid & GCFLAG_GLOBAL == 0
+        self.gc.header(s_adr).tid |= GCFLAG_POSSIBLY_OUTDATED
+        self.gc.header(t_adr).tid |= GCFLAG_LOCAL_COPY
+        set_hdr_revision(self.gc.header(t_adr), s_adr)
         self.gc.stm_operations._tldicts[1][s_adr] = t_adr
-        obj = self.gc.stm_writebarrier(s_adr)     # global copied object
+        obj = self.stm_writebarrier(s_adr)     # global copied object
         assert obj == t_adr
         assert self.gc.stm_operations._transactional_copies == []
 
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to