Author: Armin Rigo <[email protected]>
Branch: stmgc-static-barrier
Changeset: r66153:c7ed6268e742
Date: 2013-08-14 17:45 +0200
http://bitbucket.org/pypy/pypy/changeset/c7ed6268e742/

Log:    in-progress: use the 5 barriers

diff --git a/rpython/translator/stm/test/test_writebarrier.py 
b/rpython/translator/stm/test/test_writebarrier.py
--- a/rpython/translator/stm/test/test_writebarrier.py
+++ b/rpython/translator/stm/test/test_writebarrier.py
@@ -24,7 +24,7 @@
         res = self.interpret(f1, [-5])
         assert res == 42
         assert len(self.writemode) == 0
-        assert self.barriers == ['P2R']
+        assert self.barriers == ['A2R']
 
     def test_simple_write(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -37,7 +37,7 @@
         self.interpret(f1, [4])
         assert x1.foo == 4
         assert len(self.writemode) == 1
-        assert self.barriers == ['P2W']
+        assert self.barriers == ['A2W']
 
     def test_multiple_reads(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed),
@@ -58,7 +58,7 @@
         res = self.interpret(f1, [4])
         assert res == -81
         assert len(self.writemode) == 0
-        assert self.barriers == ['P2R']
+        assert self.barriers == ['A2R']
 
     def test_malloc(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -81,7 +81,7 @@
 
         self.interpret(f1, [4])
         assert len(self.writemode) == 2
-        assert self.barriers == ['P2W', 'r2w']
+        assert self.barriers == ['A2W', 'V2W']
 
     def test_repeat_read_barrier_after_malloc(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -95,7 +95,7 @@
 
         self.interpret(f1, [4])
         assert len(self.writemode) == 1
-        assert self.barriers == ['P2R']
+        assert self.barriers == ['A2R']
 
     def test_write_may_alias(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -109,10 +109,10 @@
         y = lltype.malloc(X, immortal=True)
         res = self.interpret(f1, [x, y])
         assert res == 36
-        assert self.barriers == ['P2R', 'P2W', 'p2r']
+        assert self.barriers == ['A2R', 'A2W', 'q2r']
         res = self.interpret(f1, [x, x])
         assert res == 42
-        assert self.barriers == ['P2R', 'P2W', 'P2R']
+        assert self.barriers == ['A2R', 'A2W', 'Q2R']
 
     def test_write_cannot_alias(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -127,7 +127,7 @@
         y = lltype.malloc(Y, immortal=True)
         res = self.interpret(f1, [x, y])
         assert res == 36
-        assert self.barriers == ['P2R', 'P2W']
+        assert self.barriers == ['A2R', 'A2W']
 
     def test_call_external_random_effects(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -140,7 +140,7 @@
         x = lltype.malloc(X, immortal=True); x.foo = 6
         res = self.interpret(f1, [x])
         assert res == 36
-        assert self.barriers == ['P2R', 'p2r']
+        assert self.barriers == ['A2R', 'a2r']
 
     def test_call_external_no_random_effects(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -157,7 +157,7 @@
         x = lltype.malloc(X, immortal=True); x.foo = 6
         res = self.interpret(f1, [x])
         assert res == 36
-        assert self.barriers == ['P2R']
+        assert self.barriers == ['A2R']
 
     def test_pointer_compare_0(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -190,10 +190,10 @@
         y = lltype.malloc(X, immortal=True)
         res = self.interpret(f1, [x, y])
         assert res == 0
-        assert self.barriers == ['P2W', '=']
+        assert self.barriers == ['A2W', '=']
         res = self.interpret(f1, [x, x])
         assert res == 1
-        assert self.barriers == ['P2W', '=']
+        assert self.barriers == ['A2W', '=']
 
     def test_pointer_compare_3(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -204,10 +204,10 @@
         y = lltype.malloc(X, immortal=True)
         res = self.interpret(f1, [x, y])
         assert res == 1
-        assert self.barriers == ['P2W', '=']
+        assert self.barriers == ['A2W', '=']
         res = self.interpret(f1, [x, x])
         assert res == 0
-        assert self.barriers == ['P2W', '=']
+        assert self.barriers == ['A2W', '=']
 
     def test_pointer_compare_4(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -219,10 +219,10 @@
         y = lltype.malloc(X, immortal=True)
         res = self.interpret(f1, [x, y])
         assert res == 1
-        assert self.barriers == ['P2W', 'P2W']
+        assert self.barriers == ['A2W', 'A2W']
         res = self.interpret(f1, [x, x])
         assert res == 0
-        assert self.barriers == ['P2W', 'P2W']
+        assert self.barriers == ['A2W', 'A2W']
 
     def test_simple_loop(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
@@ -235,7 +235,7 @@
         res = self.interpret(f1, [x, 5])
         assert res == 0
         # for now we get this.  Later, we could probably optimize it
-        assert self.barriers == ['P2W', 'p2w', 'p2w', 'p2w', 'p2w']
+        assert self.barriers == ['A2W', 'a2w', 'a2w', 'a2w', 'a2w']
 
     def test_subclassing(self):
         class X:
@@ -261,11 +261,11 @@
 
         res = self.interpret(f1, [10])
         assert res == 42 + 10
-        assert self.barriers == ['p2r', 'p2r', 'p2r'] # from 3 blocks (could be
+        assert self.barriers == ['a2r', 'a2r', 'a2r'] # from 3 blocks (could be
                                                       # optimized later)
         res = self.interpret(f1, [-10])
         assert res == 815
-        assert self.barriers == ['p2r', 'p2r']
+        assert self.barriers == ['a2r', 'a2r']
 
     def test_write_barrier_repeated(self):
         class X:
@@ -278,7 +278,7 @@
             return y
 
         res = self.interpret(f1, [10])
-        assert self.barriers == ['P2W', 'r2w']
+        assert self.barriers == ['A2W', 'r2w']
 
 
 external_stuff = rffi.llexternal('external_stuff', [], lltype.Void,
diff --git a/rpython/translator/stm/test/transform_support.py 
b/rpython/translator/stm/test/transform_support.py
--- a/rpython/translator/stm/test/transform_support.py
+++ b/rpython/translator/stm/test/transform_support.py
@@ -2,7 +2,7 @@
 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 NEEDS_BARRIER
+from rpython.translator.stm.writebarrier import needs_barrier
 from rpython.conftest import option
 
 
@@ -33,9 +33,9 @@
         if isinstance(p, _stmptr):
             return p._category
         if not p:
-            return 'N'
+            return None
         if p._solid:
-            return 'P'     # allocated with immortal=True
+            return 'A'     # allocated with immortal=True
         raise AssertionError("unknown category on %r" % (p,))
 
     def interpret(self, fn, args):
@@ -76,14 +76,16 @@
 
     def check_category(self, p, expected):
         cat = self.get_category_or_null(p)
-        assert cat in 'NPRW'
+        assert cat in 'AQRVW' or cat is None
+        if expected is not None:
+            assert cat is not None and cat >= expected
         return cat
 
     def op_stm_barrier(self, kind, obj):
         frm, middledigit, to = kind
         assert middledigit == '2'
         cat = self.check_category(obj, frm)
-        if not NEEDS_BARRIER[cat, to]:
+        if not needs_barrier(cat, to):
             # a barrier, but with no effect
             self.llinterpreter.tester.barriers.append(kind.lower())
             return obj
@@ -96,32 +98,38 @@
             return ptr2
 
     def op_stm_ptr_eq(self, obj1, obj2):
-        self.check_category(obj1, 'P')
-        self.check_category(obj2, 'P')
+        self.check_category(obj1, None)
+        self.check_category(obj2, None)
         self.llinterpreter.tester.barriers.append('=')
         return obj1 == obj2
 
     def op_getfield(self, obj, field):
-        if not obj._TYPE.TO._immutable_field(field):
-            self.check_category(obj, 'R')
+        if obj._TYPE.TO._immutable_field(field):
+            expected = 'I'
+        else:
+            expected = 'R'
+        self.check_category(obj, expected)
         return LLFrame.op_getfield(self, obj, field)
 
     def op_setfield(self, obj, fieldname, fieldvalue):
-        if not obj._TYPE.TO._immutable_field(fieldname):
-            self.check_category(obj, 'W')
-            # 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, 'P')
+        self.check_category(obj, 'W')
+        # convert R -> Q 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, 'Q')
         return LLFrame.op_setfield(self, obj, fieldname, fieldvalue)
 
     def op_cast_pointer(self, RESTYPE, obj):
-        cat = self.check_category(obj, 'P')
+        cat = self.check_category(obj, None)
         p = opimpl.op_cast_pointer(RESTYPE, obj)
         return _stmptr(p, cat)
     op_cast_pointer.need_result_type = True
 
     def op_malloc(self, obj, flags):
+        # convert all existing pointers W -> V
+        for p in self.all_stm_ptrs():
+            if p._category == 'W':
+                _stmptr._category.__set__(p, 'V')
         p = LLFrame.op_malloc(self, obj, flags)
         ptr2 = _stmptr(p, 'W')
         self.llinterpreter.tester.writemode.add(ptr2._obj)
diff --git a/rpython/translator/stm/transform.py 
b/rpython/translator/stm/transform.py
--- a/rpython/translator/stm/transform.py
+++ b/rpython/translator/stm/transform.py
@@ -11,6 +11,7 @@
 
     def __init__(self, translator):
         self.translator = translator
+        self.barrier_counts = {}
 
     def transform(self):
         assert not hasattr(self.translator, 'stm_transformation_applied')
@@ -30,6 +31,8 @@
         self.collect_analyzer = CollectAnalyzer(self.translator)
         for graph in self.translator.graphs:
             insert_stm_barrier(self, graph)
+        for key, value in sorted(self.barrier_counts.items()):
+            log("%s: %d barriers" % (key, value[0]))
         del self.write_analyzer
         del self.collect_analyzer
 
diff --git a/rpython/translator/stm/writebarrier.py 
b/rpython/translator/stm/writebarrier.py
--- a/rpython/translator/stm/writebarrier.py
+++ b/rpython/translator/stm/writebarrier.py
@@ -9,15 +9,6 @@
     'malloc_nonmovable', 'malloc_nonmovable_varsize',
     ])
 
-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: 
         if isinstance(v, Constant):
@@ -42,23 +33,32 @@
         return OUTER._immutable_interiorfield(unwraplist(op.args[1:-1]))
     raise AssertionError(op)
 
+def needs_barrier(frm, to):
+    return to > frm
+
 
 def insert_stm_barrier(stmtransformer, graph):
     """This function uses the following characters for 'categories':
 
-           * 'P': a general pointer
+           * 'A': any general pointer
+           * 'I': not a stub (immut_read_barrier was applied)
+           * 'Q': same as R, except needs a repeat_read_barrier
            * 'R': the read barrier was applied
+           * 'V': same as W, except needs a repeat_write_barrier
            * 'W': the write barrier was applied
+
+       The letters are chosen so that a barrier is needed to change a
+       pointer from category x to category y if and only if y > x.
     """
     graphinfo = stmtransformer.write_analyzer.compute_graph_info(graph)
 
     def get_category(v):
-        return category.get(v, 'P')
+        return category.get(v, 'A')
 
     def get_category_or_null(v):
         if isinstance(v, Constant) and not v.value:
-            return 'N'
-        return category.get(v, 'P')
+            return None
+        return category.get(v, 'A')
 
     def renamings_get(v):
         if v not in renamings:
@@ -77,26 +77,31 @@
         wants_a_barrier = {}
         expand_comparison = set()
         for op in block.operations:
-            # [1] XXX we can't leave getarraysize or the immutable getfields
-            #     fully unmodified.  We'd need at least some lightweight
-            #     read barrier to detect stubs.  For now we just put a
-            #     regular read barrier.
-            if (op.opname in ('getfield', 'getarrayitem',
-                              'getinteriorfield',
-                              'getarraysize', 'getinteriorarraysize', # XXX [1]
-                              ) and
-                  op.result.concretetype is not lltype.Void and
-                  op.args[0].concretetype.TO._gckind == 'gc' and
-                  True): #not is_immutable(op)): XXX see [1]
+            is_getter = (op.opname in ('getfield', 'getarrayitem',
+                                       'getinteriorfield') and
+                         op.result.concretetype is not lltype.Void and
+                         op.args[0].concretetype.TO._gckind == 'gc')
+            if (op.opname in ('getarraysize', 'getinteriorarraysize')
+                or (is_getter and is_immutable(op))):
+                # we can't leave getarraysize or the immutable getfields
+                # fully unmodified: we need at least immut_read_barrier
+                # to detect stubs.
+                wants_a_barrier[op] = 'I'
+
+            elif is_getter:
+                # the non-immutable getfields need a regular read barrier
                 wants_a_barrier[op] = 'R'
+
             elif (op.opname in ('setfield', 'setarrayitem',
                                 'setinteriorfield') and
                   op.args[-1].concretetype is not lltype.Void and
-                  op.args[0].concretetype.TO._gckind == 'gc' and
-                  not is_immutable(op)):
+                  op.args[0].concretetype.TO._gckind == 'gc'):
+                # setfields need a regular write barrier
                 wants_a_barrier[op] = 'W'
+
             elif (op.opname in ('ptr_eq', 'ptr_ne') and
                   op.args[0].concretetype.TO._gckind == 'gc'):
+                # GC pointer comparison might need special care
                 expand_comparison.add(op)
         #
         if wants_a_barrier or expand_comparison:
@@ -119,22 +124,20 @@
                     v_holder = renamings.setdefault(v, [v])
                     v = v_holder[0]
                     frm = get_category(v)
-                    if NEEDS_BARRIER[frm, to]:
-                        c_info = Constant('%s2%s' % (frm, to), lltype.Void)
+                    if needs_barrier(frm, to):
+                        try:
+                            b = stmtransformer.barrier_counts[frm, to]
+                        except KeyError:
+                            c_info = Constant('%s2%s' % (frm, to), lltype.Void)
+                            b = [0, c_info]
+                            stmtransformer.barrier_counts[frm, to] = b
+                        b[0] += 1
+                        c_info = b[1]
                         w = varoftype(v.concretetype)
                         newop = SpaceOperation('stm_barrier', [c_info, v], w)
                         newoperations.append(newop)
                         v_holder[0] = w
                         category[w] = to
-                        if to == 'W':
-                            # if any of the other vars in the same path
-                            # points to the same object, they must lose
-                            # their read-status now
-                            for u in block.getvariables():
-                                if get_category(u) == 'R' \
-                                  and u.concretetype == v.concretetype:
-                                    category[u] = 'P'
-                            
                 #
                 newop = SpaceOperation(op.opname,
                                        [renamings_get(v) for v in op.args],
@@ -144,7 +147,7 @@
                 if op in expand_comparison:
                     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 None not in cats and (cats[0] < 'V' or cats[1] < 'V'):
                         if newop.opname == 'ptr_ne':
                             v = varoftype(lltype.Bool)
                             negop = SpaceOperation('bool_not', [v],
@@ -155,28 +158,30 @@
 
                 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
+                    # categories back to 'V', because we would need
+                    # a repeat_write_barrier on them afterwards
                     for v, cat in category.items():
                         if cat == 'W':
-                            category[v] = 'R'
+                            category[v] = 'V'
 
                 effectinfo = stmtransformer.write_analyzer.analyze(
                     op, graphinfo=graphinfo)
                 if effectinfo:
                     if effectinfo is top_set:
                         # this operation can perform random writes: any
-                        # 'R'-category object falls back to 'P' because
-                        # we would need another stm_read_barrier()
+                        # 'R'-category object falls back to 'Q' because
+                        # we would need a repeat_read_barrier()
                         for v, cat in category.items():
                             if cat == 'R':
-                                category[v] = 'P'
+                                category[v] = 'Q'
                     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] = 'P'
+                                category[v] = 'Q'
+                        # XXX this is likely not general enough: we need
+                        # to consider 'types' or any base type
 
                 if op.opname in MALLOCS:
                     category[op.result] = 'W'
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to