Author: Armin Rigo <[email protected]>
Branch: stmgc-static-barrier
Changeset: r66154:cc00343ac4ef
Date: 2013-08-14 19:16 +0200
http://bitbucket.org/pypy/pypy/changeset/cc00343ac4ef/

Log:    Finish generating all new barrier combinations

diff --git a/rpython/translator/stm/breakfinder.py 
b/rpython/translator/stm/breakfinder.py
new file mode 100644
--- /dev/null
+++ b/rpython/translator/stm/breakfinder.py
@@ -0,0 +1,22 @@
+from rpython.translator.backendopt import graphanalyze
+from rpython.translator.simplify import get_funcobj
+
+
+TRANSACTION_BREAK = set([
+    'stm_commit_transaction',
+    'stm_begin_inevitable_transaction',
+    'stm_perform_transaction',
+    ])
+
+
+class TransactionBreakAnalyzer(graphanalyze.BoolGraphAnalyzer):
+
+    def analyze_simple_operation(self, op, graphinfo):
+        return op.opname in TRANSACTION_BREAK
+
+    def analyze_external_call(self, op, seen=None):
+        # if 'funcobj' releases the GIL, then the GIL-releasing
+        # functions themselves will call stm_commit_transaction
+        # and stm_begin_inevitable_transaction.  This case is
+        # covered above.
+        return False
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
@@ -1,3 +1,4 @@
+from rpython.rlib.rstm import register_invoke_around_extcall
 from rpython.rtyper.lltypesystem import lltype, rffi
 from rpython.translator.stm.test.transform_support import BaseTestTransform
 
@@ -129,28 +130,40 @@
         assert res == 36
         assert self.barriers == ['A2R', 'A2W']
 
-    def test_call_external_random_effects(self):
+    def test_call_external_release_gil(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
         def f1(p):
+            register_invoke_around_extcall()
             x1 = p.foo
-            external_stuff()
+            external_release_gil()
             x2 = p.foo
             return x1 * x2
 
         x = lltype.malloc(X, immortal=True); x.foo = 6
         res = self.interpret(f1, [x])
         assert res == 36
-        assert self.barriers == ['A2R', 'a2r']
+        assert self.barriers == ['A2R', 'I2R']
 
-    def test_call_external_no_random_effects(self):
+    def test_call_external_any_gcobj(self):
         X = lltype.GcStruct('X', ('foo', lltype.Signed))
-        external_stuff = rffi.llexternal('external_stuff2', [], lltype.Void,
-                                         _callable=lambda: None,
-                                         random_effects_on_gcobjs=False,
-                                         threadsafe=False)
         def f1(p):
+            register_invoke_around_extcall()
             x1 = p.foo
-            external_stuff()
+            external_any_gcobj()
+            x2 = p.foo
+            return x1 * x2
+
+        x = lltype.malloc(X, immortal=True); x.foo = 6
+        res = self.interpret(f1, [x])
+        assert res == 36
+        assert self.barriers == ['A2R', 'q2r']
+
+    def test_call_external_safest(self):
+        X = lltype.GcStruct('X', ('foo', lltype.Signed))
+        def f1(p):
+            register_invoke_around_extcall()
+            x1 = p.foo
+            external_safest()
             x2 = p.foo
             return x1 * x2
 
@@ -253,7 +266,7 @@
                 x = Z()
                 x.foo = 815
                 x.zbar = 'A'
-            external_stuff()
+            external_any_gcobj()
             result = x.foo          # 1
             if isinstance(x, Y):    # 2
                 result += x.ybar    # 3
@@ -261,11 +274,11 @@
 
         res = self.interpret(f1, [10])
         assert res == 42 + 10
-        assert self.barriers == ['a2r', 'a2r', 'a2r'] # from 3 blocks (could be
+        assert self.barriers == ['a2r', 'a2i', 'a2r'] # from 3 blocks (could be
                                                       # optimized later)
         res = self.interpret(f1, [-10])
         assert res == 815
-        assert self.barriers == ['a2r', 'a2r']
+        assert self.barriers == ['a2r', 'a2i']
 
     def test_write_barrier_repeated(self):
         class X:
@@ -278,10 +291,18 @@
             return y
 
         res = self.interpret(f1, [10])
-        assert self.barriers == ['A2W', 'r2w']
+        assert self.barriers == ['A2W', 'V2W']
 
 
-external_stuff = rffi.llexternal('external_stuff', [], lltype.Void,
-                                 _callable=lambda: None,
-                                 random_effects_on_gcobjs=True,
-                                 threadsafe=False)
+external_release_gil = rffi.llexternal('external_release_gil', [], lltype.Void,
+                                       _callable=lambda: None,
+                                       random_effects_on_gcobjs=True,
+                                       threadsafe=True)   # GIL is released
+external_any_gcobj = rffi.llexternal('external_any_gcobj', [], lltype.Void,
+                                     _callable=lambda: None,
+                                     random_effects_on_gcobjs=True,
+                                     threadsafe=False)   # GIL is not released
+external_safest = rffi.llexternal('external_safest', [], lltype.Void,
+                                  _callable=lambda: None,
+                                  random_effects_on_gcobjs=False,
+                                  threadsafe=False)   # GIL is not released
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
@@ -76,7 +76,7 @@
 
     def check_category(self, p, expected):
         cat = self.get_category_or_null(p)
-        assert cat in 'AQRVW' or cat is None
+        assert cat in 'AIQRVW' or cat is None
         if expected is not None:
             assert cat is not None and cat >= expected
         return cat
@@ -104,28 +104,33 @@
         return obj1 == obj2
 
     def op_getfield(self, obj, field):
-        if obj._TYPE.TO._immutable_field(field):
-            expected = 'I'
-        else:
-            expected = 'R'
-        self.check_category(obj, expected)
+        if obj._TYPE.TO._gckind == 'gc':
+            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):
-        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')
+        if obj._TYPE.TO._gckind == 'gc':
+            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, None)
-        p = opimpl.op_cast_pointer(RESTYPE, obj)
-        return _stmptr(p, cat)
+        if obj._TYPE.TO._gckind == 'gc':
+            cat = self.check_category(obj, None)
+            p = opimpl.op_cast_pointer(RESTYPE, obj)
+            return _stmptr(p, cat)
+        return LLFrame.op_cast_pointer(self, RESTYPE, obj)
     op_cast_pointer.need_result_type = True
 
     def op_malloc(self, obj, flags):
+        assert flags['flavor'] == 'gc'
         # convert all existing pointers W -> V
         for p in self.all_stm_ptrs():
             if p._category == 'W':
@@ -134,3 +139,15 @@
         ptr2 = _stmptr(p, 'W')
         self.llinterpreter.tester.writemode.add(ptr2._obj)
         return ptr2
+
+    def transaction_break(self):
+        # convert -> I all other pointers to the same object we can find
+        for p in self.all_stm_ptrs():
+            if p._category > 'I':
+                _stmptr._category.__set__(p, 'I')
+
+    def op_stm_commit_transaction(self):
+        self.transaction_break()
+
+    def op_stm_begin_inevitable_transaction(self):
+        self.transaction_break()
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
@@ -3,6 +3,7 @@
 from rpython.translator.stm.inevitable import insert_turn_inevitable
 from rpython.translator.stm.jitdriver import reorganize_around_jit_driver
 from rpython.translator.stm.threadlocalref import transform_tlref
+from rpython.translator.stm.breakfinder import TransactionBreakAnalyzer
 from rpython.translator.c.support import log
 from rpython.memory.gctransform.framework import CollectAnalyzer
 
@@ -29,12 +30,14 @@
     def transform_write_barrier(self):
         self.write_analyzer = WriteAnalyzer(self.translator)
         self.collect_analyzer = CollectAnalyzer(self.translator)
+        self.break_analyzer = TransactionBreakAnalyzer(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
+        del self.break_analyzer
 
     def transform_turn_inevitable(self):
         for graph in self.translator.graphs:
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
@@ -156,6 +156,15 @@
                             newop.result = v
                         newop.opname = 'stm_ptr_eq'
 
+                if stmtransformer.break_analyzer.analyze(op):
+                    # this operation can perform a transaction break:
+                    # all pointers are lowered to 'I', because a non-
+                    # stub cannot suddenly point to a stub, but we
+                    # cannot guarantee anything more
+                    for v, cat in category.items():
+                        if cat > 'I':
+                            category[v] = 'I'
+
                 if stmtransformer.collect_analyzer.analyze(op):
                     # this operation can collect: we bring all 'W'
                     # categories back to 'V', because we would need
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to