[pypy-commit] pypy stmgc-c8-dictstrategy: hg merge stmgc-c8

arigo noreply at buildbot.pypy.org
Wed Nov 25 11:17:31 EST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: stmgc-c8-dictstrategy
Changeset: r80956:e884e0b2b29f
Date: 2015-11-25 17:18 +0100
http://bitbucket.org/pypy/pypy/changeset/e884e0b2b29f/

Log:	hg merge stmgc-c8

diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -93,6 +93,7 @@
         insets = self._in_states
         #
         # get input variables and their states:
+        assert len(insets[block]) == len(block.inputargs)
         writeable = {}
         for v, state in zip(block.inputargs, insets[block]):
             writeable[v] = state
@@ -106,8 +107,10 @@
                 writeable = {}
             #
             if op.opname == "stm_ignored_start":
+                assert not self.in_stm_ignored
                 self.in_stm_ignored = True
             elif op.opname == "stm_ignored_stop":
+                assert self.in_stm_ignored
                 self.in_stm_ignored = False
             elif op.opname == "gc_writebarrier":
                 assert not self.in_stm_ignored
@@ -115,67 +118,62 @@
             elif op.opname == "malloc":
                 rtti = get_rtti(op.args[0].value)
                 if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'):
-                    # XXX: not sure why that matters, copied from
-                    # find_initializing_stores
-                    continue
-                writeable[op.result] = True
+                    # objs with finalizers are allocated directly as "old", so
+                    # they need write barriers
+                    assert op not in self.clean_ops
+                else:
+                    # freshly allocated object
+                    writeable[op.result] = True
                 #
             elif op.opname in ("cast_pointer", "same_as"):
-                if writeable.get(op.args[0], False):
-                    writeable[op.result] = True
+                writeable[op.result] = writeable.get(op.args[0], False)
                 #
             elif op.opname in ('setfield', 'setarrayitem', 'setinteriorfield', 'raw_store'):
+                # generic_set case
                 if op.args[-1].concretetype == lltype.Void:
+                    # always ignore setfields of Void type
                     self.clean_ops.add(op)
-                    continue # ignore setfields of Void type
                 elif not var_needsgc(op.args[0]):
+                    # setfields on raw don't need a barrier
                     if (var_needsgc(op.args[-1]) and
                         'is_excdata' not in op.args[0].concretetype.TO._hints):
                         raise Exception("%s: GC pointer written into a non-GC location"
                                         % (op,))
                     self.clean_ops.add(op)
-                    continue
                 elif self.in_stm_ignored:
-                    # detect if we're inside a 'stm_ignored' block and in
-                    # that case don't call stm_write().  This only works for
-                    # writing non-GC pointers.
+                    # within stm_ignored, don't emit stm_write(). This only works
+                    # for writing non-GC pointers.
                     if var_needsgc(op.args[-1]):
                         raise Exception("in stm_ignored block: write of a gc pointer")
                     self.clean_ops.add(op)
-                    continue
-                elif self._set_into_gc_array_part(op) is None:
-                    # full write barrier required
-                    if writeable.get(op.args[0], False):
-                        # already writeable, this op is also clean
-                        self.clean_ops.add(op)
-                    elif op in self.clean_ops:
-                        # we changed our opinion in this iteration
-                        self.clean_ops.remove(op)
-                    # always writeable after this op
-                    writeable[op.args[0]] = True
                 else:
-                    # things that need partial write barriers (card marking)
+                    # we need a (partial) write barrier if arg0 is not writeable
                     if writeable.get(op.args[0], False):
                         self.clean_ops.add(op)
                     elif op in self.clean_ops:
                         self.clean_ops.remove(op)
+                    #
+                    if self._set_into_gc_array_part(op) is None:
+                        # this will do a full write barrier, not card marking
+                        # arg0 is always writeable afterwards
+                        writeable[op.args[0]] = True
         #
         # update in_states of all successors
-        updated = set()
+        to_do = set()
         for link in block.exits:
             succ = link.target
             outset = [writeable.get(v, False) for v in link.args]
             if succ in insets:
-                to_merge = [insets[succ], outset]
-                new = self._merge_out_states(to_merge)
-                if new != insets[succ]:
-                    updated.add(succ)
+                old = insets[succ]
+                new = self._merge_out_states([old, outset])
+                if new != old:
+                    to_do.add(succ)
                     insets[succ] = new
             else:
                 # block not processed yet
                 insets[succ] = outset
-                updated.add(succ)
-        return updated
+                to_do.add(succ)
+        return to_do
 
 
     def collect(self):
@@ -186,8 +184,7 @@
         graph = self.graph
         #
         # initialize blocks
-        self._in_states = {}
-        self._in_states[graph.startblock] = [False] * len(graph.startblock.inputargs)
+        self._in_states = {graph.startblock: [False] * len(graph.startblock.inputargs)}
         #
         # fixpoint iteration
         # XXX: reverse postorder traversal
diff --git a/rpython/memory/gctransform/test/test_framework.py b/rpython/memory/gctransform/test/test_framework.py
--- a/rpython/memory/gctransform/test/test_framework.py
+++ b/rpython/memory/gctransform/test/test_framework.py
@@ -396,6 +396,141 @@
     assert summary(ff)['stm_write'] == 3
 
 
+def test_remove_write_barrier_stm4():
+    from rpython.translator.c.genc import CStandaloneBuilder
+    from rpython.flowspace.model import summary
+
+    rS = lltype.Struct('rS')
+    S = lltype.GcStruct('S')
+    rA = lltype.Array(lltype.Ptr(rS))
+    A = lltype.GcArray(lltype.Ptr(S))
+    Ar = lltype.GcArray(lltype.Ptr(rS))
+    def f(ra, a, ar, i):
+        s = lltype.malloc(S)
+        rs = lltype.malloc(rS, flavor='raw')
+        ra[0] = rs
+        ra[1] = rs
+        a[0] = s
+        a[1] = s
+        ar[0] = rs
+        ar[1] = rs
+    def g(argv):
+        n = int(argv[1])
+        ra = lltype.malloc(rA, n, flavor='raw')
+        a = lltype.malloc(A, n)
+        ar = lltype.malloc(Ar, n)
+        f(ra, a, ar, n)
+        return 0
+    t = rtype(g, [s_list_of_strings])
+    t.config.translation.stm = True
+    gcpolicy = StmFrameworkGcPolicy
+    t.config.translation.gc = "stmgc"
+    cbuild = CStandaloneBuilder(t, g, t.config,
+                                gcpolicy=gcpolicy)
+    db = cbuild.generate_graphs_for_llinterp()
+
+    ff = graphof(t, f)
+    #ff.show()
+    assert summary(ff)['stm_write'] == 4
+
+def test_remove_write_barrier_stm5():
+    from rpython.translator.c.genc import CStandaloneBuilder
+    from rpython.flowspace.model import summary
+
+    class B(object):
+        def __del__(self):
+            pass
+    class A(object): pass
+    def f():
+        b = B()
+        b.x = 1 # needs WB bc. of finalizer
+        a = A()
+        a.x = 1
+    def g(argv):
+        f()
+        return 0
+    t = rtype(g, [s_list_of_strings])
+    t.config.translation.stm = True
+    gcpolicy = StmFrameworkGcPolicy
+    t.config.translation.gc = "stmgc"
+    cbuild = CStandaloneBuilder(t, g, t.config,
+                                gcpolicy=gcpolicy)
+    db = cbuild.generate_graphs_for_llinterp()
+
+    ff = graphof(t, f)
+    #ff.show()
+    assert summary(ff)['stm_write'] == 1
+
+def test_remove_write_barrier_stm6():
+    from rpython.translator.c.genc import CStandaloneBuilder
+    from rpython.flowspace.model import summary
+    #
+    rSi = lltype.Struct('rSi', ('i', lltype.Signed))
+    rSr = lltype.Struct('rSr', ('s', lltype.Ptr(rSi)))
+    Si = lltype.GcStruct('Si', ('i', lltype.Signed))
+    Ss = lltype.GcStruct('Ss', ('s', lltype.Ptr(Si)))
+    Sr = lltype.GcStruct('Sr', ('r', lltype.Ptr(rSi)))
+    def f(rsi, rsr, si, ss, sr):
+        rsi.i = 0
+        rsr.s = rsi
+        si.i = 0
+        ss.s = si
+        sr.r = rsi
+    def g(argv):
+        rsi = lltype.malloc(rSi, flavor='raw')
+        rsr = lltype.malloc(rSr, flavor='raw')
+        si = lltype.malloc(Si, flavor='gc')
+        ss = lltype.malloc(Ss, flavor='gc')
+        sr = lltype.malloc(Sr, flavor='gc')
+        f(rsi, rsr, si, ss, sr)
+        return 0
+    t = rtype(g, [s_list_of_strings])
+    t.config.translation.stm = True
+    gcpolicy = StmFrameworkGcPolicy
+    t.config.translation.gc = "stmgc"
+    cbuild = CStandaloneBuilder(t, g, t.config,
+                                gcpolicy=gcpolicy)
+    db = cbuild.generate_graphs_for_llinterp()
+
+    ff = graphof(t, f)
+    #ff.show()
+    assert summary(ff)['stm_write'] == 3
+
+def test_remove_write_barrier_stm7():
+    from rpython.translator.c.genc import CStandaloneBuilder
+    from rpython.flowspace.model import summary
+    #
+    rSi = lltype.Struct('rSi', ('i', lltype.Signed))
+    rSr = lltype.Struct('rSr', ('s', rSi))
+    Si = lltype.GcStruct('Si', ('i', lltype.Signed))
+    Ss = lltype.GcStruct('Ss', ('s', Si))
+    Sr = lltype.GcStruct('Sr', ('r', rSi))
+    def f(rsi, rsr, si, ss, sr):
+        rsi.i = 0
+        rsr.s.i = 0
+        si.i = 0
+        ss.s.i = 0
+        sr.r.i = 0
+    def g(argv):
+        rsi = lltype.malloc(rSi, flavor='raw')
+        rsr = lltype.malloc(rSr, flavor='raw')
+        si = lltype.malloc(Si, flavor='gc')
+        ss = lltype.malloc(Ss, flavor='gc')
+        sr = lltype.malloc(Sr, flavor='gc')
+        f(rsi, rsr, si, ss, sr)
+        return 0
+    t = rtype(g, [s_list_of_strings])
+    t.config.translation.stm = True
+    gcpolicy = StmFrameworkGcPolicy
+    t.config.translation.gc = "stmgc"
+    cbuild = CStandaloneBuilder(t, g, t.config,
+                                gcpolicy=gcpolicy)
+    db = cbuild.generate_graphs_for_llinterp()
+
+    ff = graphof(t, f)
+    #ff.show()
+    assert summary(ff)['stm_write'] == 3
+
 def test_write_barrier_collector():
     class A(object):
         pass
@@ -483,6 +618,34 @@
     print "\n".join(map(str,wbc.clean_ops))
     assert len(wbc.clean_ops) == 11
 
+def test_write_barrier_collector_stm_inevitable_interaction():
+    from rpython.translator.c.genc import CStandaloneBuilder
+    from rpython.flowspace.model import summary
+    #
+    rS = lltype.Struct('rS', ('i', lltype.Signed))
+    S = lltype.GcStruct('S', ('i', lltype.Signed))
+    def f():
+        rs = lltype.malloc(rS, flavor='raw')
+        s = lltype.malloc(S, flavor='gc')
+        rs.i = 5 # become_inevitable setfield on 'raw'
+        s.i = 6 # become_inevitable canmalloc -> needs WB
+    def g(argv):
+        f()
+        return 0
+    t = rtype(g, [s_list_of_strings])
+    t.config.translation.stm = True
+    gcpolicy = StmFrameworkGcPolicy
+    t.config.translation.gc = "stmgc"
+    cbuild = CStandaloneBuilder(t, g, t.config,
+                                gcpolicy=gcpolicy)
+    db = cbuild.generate_graphs_for_llinterp()
+
+    ff = graphof(t, f)
+    #ff.show()
+    assert summary(ff)['stm_write'] == 1
+
+
+
 def test_write_barrier_collector_loops():
     class A(object):
         pass
diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py
--- a/rpython/rlib/rgc.py
+++ b/rpython/rlib/rgc.py
@@ -53,7 +53,7 @@
     """
     _pinned_objects.append(obj)
     return True
-        
+
 
 class PinEntry(ExtRegistryEntry):
     _about_ = pin
@@ -296,6 +296,10 @@
     slowpath = False
     if stm_is_enabled():
         slowpath = True
+        # seems to be a good idea to do a *full* write barrier on the
+        # items array, as this prevents repeated stm_write_card() inside
+        # the loop below (see logic in stmframework.py).
+        llop.gc_writebarrier(lltype.Void, dest)
         #
     elif _contains_gcptr(TP.OF):
         # perform a write barrier that copies necessary flags from
@@ -864,7 +868,7 @@
             pending.extend(get_rpy_referents(gcref))
 
 all_typeids = {}
-        
+
 def get_typeid(obj):
     raise Exception("does not work untranslated")
 
diff --git a/rpython/translator/stm/funcgen.py b/rpython/translator/stm/funcgen.py
--- a/rpython/translator/stm/funcgen.py
+++ b/rpython/translator/stm/funcgen.py
@@ -416,8 +416,10 @@
     arg1 = funcgen.expr(op.args[1])
     arg2 = funcgen.expr(op.args[2])
     result = funcgen.expr(op.result)
-    return ('%s = stm_hashtable_iter_next(%s, %s, %s);' %
-            (result, arg0, arg1, arg2))
+    typename = cdecl(funcgen.lltypename(op.result), '')
+    return ('%s = (%s)stm_hashtable_iter_next((object_t *)%s, %s,'
+            ' (stm_hashtable_entry_t **)%s);' %
+            (result, typename, arg0, arg1, arg2))
 
 def stm_hashtable_iter_tracefn(funcgen, op):
     arg0 = funcgen.expr(op.args[0])
diff --git a/rpython/translator/stm/readbarrier.py b/rpython/translator/stm/readbarrier.py
--- a/rpython/translator/stm/readbarrier.py
+++ b/rpython/translator/stm/readbarrier.py
@@ -146,7 +146,7 @@
                 cat_map[op.result] = 'R'
             #
             if op.opname in ('setfield', 'setarrayitem', 'setinteriorfield',
-                             'raw_store'):
+                             'raw_store', 'gc_writebarrier'):
                 # compare with logic in stmframework.py
                 # ops that need a write barrier also make the var 'R'
                 if (op.args[-1].concretetype is not lltype.Void


More information about the pypy-commit mailing list