Author: Armin Rigo <[email protected]>
Branch: stm-thread
Changeset: r54901:85ba9ec36d90
Date: 2012-05-05 20:20 +0200
http://bitbucket.org/pypy/pypy/changeset/85ba9ec36d90/

Log:    Implement the TransactionBreakAnalyzer, needed in this version of
        STM. A variable pointing to a local object can again point to a
        global object later, and thus will need another stm_writebarrier.

diff --git a/pypy/rlib/rstm.py b/pypy/rlib/rstm.py
--- a/pypy/rlib/rstm.py
+++ b/pypy/rlib/rstm.py
@@ -6,11 +6,13 @@
     stmgcintf.StmOperations.commit_transaction()
 before_external_call._gctransformer_hint_cannot_collect_ = True
 before_external_call._dont_reach_me_in_del_ = True
+before_external_call._transaction_break_ = True
 
 def after_external_call():
     stmgcintf.StmOperations.begin_inevitable_transaction()
 after_external_call._gctransformer_hint_cannot_collect_ = True
 after_external_call._dont_reach_me_in_del_ = True
+after_external_call._transaction_break_ = True
 
 def enter_callback_call():
     new_thread = stmgcintf.StmOperations.descriptor_init()
@@ -18,6 +20,7 @@
     return new_thread
 enter_callback_call._gctransformer_hint_cannot_collect_ = True
 enter_callback_call._dont_reach_me_in_del_ = True
+enter_callback_call._transaction_break_ = True
 
 def leave_callback_call(token):
     stmgcintf.StmOperations.commit_transaction()
@@ -25,8 +28,10 @@
         stmgcintf.StmOperations.descriptor_done()
 leave_callback_call._gctransformer_hint_cannot_collect_ = True
 leave_callback_call._dont_reach_me_in_del_ = True
+leave_callback_call._transaction_break_ = True
 
 def do_yield_thread():
     stmgcintf.StmOperations.do_yield_thread()
 do_yield_thread._gctransformer_hint_close_stack_ = True
 do_yield_thread._dont_reach_me_in_del_ = True
+do_yield_thread._transaction_break_ = True
diff --git a/pypy/translator/stm/gcsource.py b/pypy/translator/stm/gcsource.py
--- a/pypy/translator/stm/gcsource.py
+++ b/pypy/translator/stm/gcsource.py
@@ -1,6 +1,7 @@
 from pypy.objspace.flow.model import Variable
 from pypy.rpython.lltypesystem import lltype, rclass
 from pypy.translator.simplify import get_graph
+from pypy.translator.backendopt import graphanalyze
 
 
 COPIES_POINTER = set([
@@ -110,6 +111,43 @@
     return resultlist
 
 
+class TransactionBreakAnalyzer(graphanalyze.BoolGraphAnalyzer):
+    """This analyzer looks for function calls that may ultimately
+    cause a transaction break (end of previous transaction, start
+    of next one)."""
+
+    def analyze_direct_call(self, graph, seen=None):
+        try:
+            func = graph.func
+        except AttributeError:
+            pass
+        else:
+            if getattr(func, '_transaction_break_', False):
+                return True
+        return graphanalyze.GraphAnalyzer.analyze_direct_call(self, graph,
+                                                              seen)
+
+    def analyze_simple_operation(self, op, graphinfo):
+        return op.opname in ('stm_start_transaction',
+                             'stm_stop_transaction')
+
+
+def enum_transactionbroken_vars(translator):
+    transactionbreak_analyzer = TransactionBreakAnalyzer(translator)
+    transactionbreak_analyzer.analyze_all()
+    for graph in translator.graphs:
+        for block in graph.iterblocks():
+            livevars = set()
+            for link in block.exits:
+                livevars |= set(link.args) - set(link.getextravars())
+            for op in block.operations[::-1]:
+                livevars.discard(op.result)
+                if transactionbreak_analyzer.analyze(op):
+                    for v in livevars:
+                        yield v
+                livevars.update(op.args)
+
+
 class GcSource(object):
     """Works like a dict {gcptr-var: set-of-sources}.  A source is a
     Constant, or a SpaceOperation that creates the value, or a string
@@ -120,6 +158,8 @@
         self._backmapping = {}
         for v1, v2 in enum_gc_dependencies(translator):
             self._backmapping.setdefault(v2, []).append(v1)
+        for v2 in enum_transactionbroken_vars(translator):
+            self._backmapping.setdefault(v2, []).append('transactionbreak')
 
     def __getitem__(self, variable):
         result = set()
diff --git a/pypy/translator/stm/test/test_gcsource.py 
b/pypy/translator/stm/test/test_gcsource.py
--- a/pypy/translator/stm/test/test_gcsource.py
+++ b/pypy/translator/stm/test/test_gcsource.py
@@ -149,3 +149,26 @@
     s = gsrc[v_result]
     assert len(s) == 1
     assert list(s)[0].opname == 'hint'
+
+def test_transactionbroken():
+    def break_transaction():
+        pass
+    break_transaction._transaction_break_ = True
+    #
+    def main(n):
+        x = X(n)
+        break_transaction()
+        return x
+    gsrc = gcsource(main, [int])
+    v_result = gsrc.translator.graphs[0].getreturnvar()
+    s = gsrc[v_result]
+    assert 'transactionbreak' in s
+    #
+    def main(n):
+        break_transaction()
+        x = X(n)
+        return x
+    gsrc = gcsource(main, [int])
+    v_result = gsrc.translator.graphs[0].getreturnvar()
+    s = gsrc[v_result]
+    assert 'transactionbreak' not in s
diff --git a/pypy/translator/stm/transform.py b/pypy/translator/stm/transform.py
--- a/pypy/translator/stm/transform.py
+++ b/pypy/translator/stm/transform.py
@@ -330,6 +330,3 @@
             for link in block.exits:
                 link.args = [renames.get(v, v) for v in link.args]
         block.operations = newoperations
-
-# XXX must repeat stm_writebarrier after doing something that can
-# go to the next transaction
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to