Commits

Remi Meier  committed b8c3b47 Merge

merge (I should pull before doing things..)

  • Participants
  • Parent commits fd2553f, 21348e8
  • Branches stmgc-c4

Comments (0)

Files changed (4)

File rpython/translator/stm/test/test_writebarrier.py

         res = self.interpret(f1, [-5])
         assert res == 42
         assert len(self.writemode) == 0
-        assert self.barriers == ['G2R']
+        assert self.barriers == ['P2R']
 
     def test_simple_write(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
         self.interpret(f1, [4])
         assert x1.foo == 4
         assert len(self.writemode) == 1
-        assert self.barriers == ['G2W']
+        assert self.barriers == ['P2W']
 
     def test_multiple_reads(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed),
         res = self.interpret(f1, [4])
         assert res == -81
         assert len(self.writemode) == 0
-        assert self.barriers == ['G2R']
+        assert self.barriers == ['P2R']
 
     def test_malloc(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
 
         self.interpret(f1, [4])
         assert len(self.writemode) == 2
-        assert self.barriers == ['G2W', 'r2w']
+        assert self.barriers == ['P2W', 'r2w']
 
     def test_repeat_read_barrier_after_malloc(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
 
         self.interpret(f1, [4])
         assert len(self.writemode) == 1
-        assert self.barriers == ['G2R']
+        assert self.barriers == ['P2R']
 
     def test_write_may_alias(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
         y = lltype.malloc(X, immortal=True)
         res = self.interpret(f1, [x, y])
         assert res == 36
-        assert self.barriers == ['P2R', 'P2W', 'o2r']
+        assert self.barriers == ['P2R', 'P2W', 'p2r']
         res = self.interpret(f1, [x, x])
         assert res == 42
-        assert self.barriers == ['P2R', 'P2W', 'O2R']
+        assert self.barriers == ['P2R', 'P2W', 'P2R']
 
     def test_write_cannot_alias(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
                 x.foo = 815
                 x.zbar = 'A'
             external_stuff()
-            result = x.foo
-            if isinstance(x, Y):
-                result += x.ybar
+            result = x.foo          # 1
+            if isinstance(x, Y):    # 2
+                result += x.ybar    # 3
             return result
 
         res = self.interpret(f1, [10])
         assert res == 42 + 10
-        assert self.barriers == ['p2r', 'p2r']  # from two blocks (could be
-                                                # optimized later)
+        assert self.barriers == ['p2r', 'p2r', 'p2r'] # from 3 blocks (could be
+                                                      # optimized later)
         res = self.interpret(f1, [-10])
         assert res == 815
-        assert self.barriers == ['p2r']
+        assert self.barriers == ['p2r', 'p2r']
+
+    def test_write_barrier_repeated(self):
+        class X:
+            pass
+        x = X()
+        def f1(i):
+            x.a = i   # write barrier
+            y = X()   # malloc
+            x.a += 1  # write barrier again
+            return y
+
+        res = self.interpret(f1, [10])
+        assert self.barriers == ['P2W', 'r2w']
 
 
 external_stuff = rffi.llexternal('external_stuff', [], lltype.Void,

File rpython/translator/stm/test/transform_support.py

 from rpython.rtyper.llinterp import LLFrame
 from rpython.rtyper.test.test_llinterp import get_interpreter, clear_tcache
 from rpython.translator.stm.transform import STMTransformer
-from rpython.translator.stm.writebarrier import MORE_PRECISE_CATEGORIES
+from rpython.translator.stm.writebarrier import NEEDS_BARRIER
 from rpython.conftest import option
 
 
         self.writemode = set()
         self.barriers = []
 
-    def get_category(self, p):
+    def get_category_or_null(self, p):
         if isinstance(p, _stmptr):
             return p._category
         if not p:
             return 'N'
         if p._solid:
-            return 'G'     # allocated with immortal=True
+            return 'P'     # allocated with immortal=True
         raise AssertionError("unknown category on %r" % (p,))
 
     def interpret(self, fn, args):
                 if isinstance(value, _stmptr):
                     yield value
 
-    def get_category(self, p):
-        return self.llinterpreter.tester.get_category(p)
+    def get_category_or_null(self, p):
+        return self.llinterpreter.tester.get_category_or_null(p)
 
     def check_category(self, p, expected):
-        cat = self.get_category(p)
-        assert cat in MORE_PRECISE_CATEGORIES[expected]
+        cat = self.get_category_or_null(p)
+        assert cat in 'NPRW'
         return cat
 
     def op_stm_barrier(self, kind, obj):
         frm, middledigit, to = kind
         assert middledigit == '2'
         cat = self.check_category(obj, frm)
-        if cat in MORE_PRECISE_CATEGORIES[to]:
+        if not NEEDS_BARRIER[cat, to]:
             # a barrier, but with no effect
             self.llinterpreter.tester.barriers.append(kind.lower())
             return obj
     def op_setfield(self, obj, fieldname, fieldvalue):
         if not obj._TYPE.TO._immutable_field(fieldname):
             self.check_category(obj, 'W')
-            # convert R -> O all other pointers to the same object we can find
+            # convert R -> P all other pointers to the same object we can find
             for p in self.all_stm_ptrs():
                 if p._category == 'R' and p._T == obj._T and p == obj:
-                    _stmptr._category.__set__(p, 'O')
+                    _stmptr._category.__set__(p, 'P')
         return LLFrame.op_setfield(self, obj, fieldname, fieldvalue)
 
     def op_cast_pointer(self, RESTYPE, obj):

File rpython/translator/stm/transform.py

 from rpython.translator.stm.jitdriver import reorganize_around_jit_driver
 from rpython.translator.stm.threadlocalref import transform_tlref
 from rpython.translator.c.support import log
+from rpython.memory.gctransform.framework import CollectAnalyzer
 
 
 class STMTransformer(object):
 
     def transform_write_barrier(self):
         self.write_analyzer = WriteAnalyzer(self.translator)
+        self.collect_analyzer = CollectAnalyzer(self.translator)
         for graph in self.translator.graphs:
             insert_stm_barrier(self, graph)
         del self.write_analyzer
+        del self.collect_analyzer
 
     def transform_turn_inevitable(self):
         for graph in self.translator.graphs:

File rpython/translator/stm/writebarrier.py

     'malloc_nonmovable', 'malloc_nonmovable_varsize',
     ])
 
-MORE_PRECISE_CATEGORIES = {
-    'P': 'PGORLWN',     # Pointer: the most general category
-    'G': 'GN',          # Global: known to be a non-local pointer
-    'O': 'ORLWN',       # Old: used to be read-ready, but maybe someone wrote
-    'R': 'RLWN',        # Read-ready: direct reads from there are ok
-    'L': 'LWN',         # Local: a local pointer
-    'W': 'WN',          # Write-ready: direct writes here are ok
-    'N': 'N'}           # NULL (the other categories also all contain NULL)
+NEEDS_BARRIER = {
+    ('P', 'R'): True,
+    ('P', 'W'): True,
+    ('R', 'R'): False,
+    ('R', 'W'): True,
+    ('W', 'R'): False,
+    ('W', 'W'): False,
+    }
 
 def unwraplist(list_v):
     for v in list_v: 
 
 
 def insert_stm_barrier(stmtransformer, graph):
+    """This function uses the following characters for 'categories':
+
+           * 'P': a general pointer
+           * 'R': the read barrier was applied
+           * 'W': the write barrier was applied
+    """
     graphinfo = stmtransformer.write_analyzer.compute_graph_info(graph)
 
     def get_category(v):
-        if isinstance(v, Constant):
-            if v.value:
-                return 'G'
-            else:
-                return 'N'     # NULL
+        return category.get(v, 'P')
+
+    def get_category_or_null(v):
+        if isinstance(v, Constant) and not v.value:
+            return 'N'
         return category.get(v, 'P')
 
     def renamings_get(v):
                   op.result.concretetype is not lltype.Void and
                   op.args[0].concretetype.TO._gckind == 'gc' and
                   True): #not is_immutable(op)): XXX see [1]
-                wants_a_barrier.setdefault(op, 'R')
+                wants_a_barrier[op] = 'R'
             elif (op.opname in ('setfield', 'setarrayitem',
                                 'setinteriorfield') and
                   op.args[-1].concretetype is not lltype.Void and
                     v_holder = renamings.setdefault(v, [v])
                     v = v_holder[0]
                     frm = get_category(v)
-                    if frm not in MORE_PRECISE_CATEGORIES[to]:
+                    if NEEDS_BARRIER[frm, to]:
                         c_info = Constant('%s2%s' % (frm, to), lltype.Void)
                         w = varoftype(v.concretetype)
                         newop = SpaceOperation('stm_barrier', [c_info, v], w)
                 newoperations.append(newop)
                 #
                 if op in expand_comparison:
-                    cats = ''.join([get_category(v) for v in newop.args])
-                    if ('N' not in cats and
-                            cats not in ('LL', 'LW', 'WL', 'WW')):
+                    cats = (get_category_or_null(newop.args[0]),
+                            get_category_or_null(newop.args[1]))
+                    if 'N' not in cats and cats != ('W', 'W'):
                         if newop.opname == 'ptr_ne':
                             v = varoftype(lltype.Bool)
                             negop = SpaceOperation('bool_not', [v],
                             newoperations.append(negop)
                             newop.result = v
                         newop.opname = 'stm_ptr_eq'
-                #
+
+                if stmtransformer.collect_analyzer.analyze(op):
+                    # this operation can collect: we bring all 'W'
+                    # categories back to 'R', because we would need
+                    # another stm_write_barrier on them afterwards
+                    for v, cat in category.items():
+                        if cat == 'W':
+                            category[v] = 'R'
+
                 effectinfo = stmtransformer.write_analyzer.analyze(
                     op, graphinfo=graphinfo)
                 if effectinfo:
                     if effectinfo is top_set:
-                        category.clear()
+                        # this operation can perform random writes: any
+                        # 'R'-category object falls back to 'P' because
+                        # we would need another stm_read_barrier()
+                        for v, cat in category.items():
+                            if cat == 'R':
+                                category[v] = 'P'
                     else:
+                        # the same, but only on objects of the right types
                         types = set([entry[1] for entry in effectinfo])
                         for v in category.keys():
                             if v.concretetype in types and category[v] == 'R':
-                                category[v] = 'O'
-                #
+                                category[v] = 'P'
+
                 if op.opname in MALLOCS:
-                    # write barriers after a possible minor collection
-                    # are not valid anymore:
-                    for v, c in category.items():
-                        if c == 'W':
-                            category[v] = 'R'
                     category[op.result] = 'W'
 
             block.operations = newoperations