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

Log:    Analyze statically which calls can eventually cause transaction
        breaks. For any such call, the variables around the call can switch
        back from LOCAL to GLOBAL.

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.unsimplify import split_block
 from pypy.translator.backendopt import graphanalyze
 
 
@@ -132,20 +133,36 @@
                              'stm_stop_transaction')
 
 
-def enum_transactionbroken_vars(translator):
-    transactionbreak_analyzer = TransactionBreakAnalyzer(translator)
-    transactionbreak_analyzer.analyze_all()
+def enum_transactionbroken_vars(translator, transactionbreak_analyzer):
+    if transactionbreak_analyzer is None:
+        return    # for tests only
     for graph in translator.graphs:
         for block in graph.iterblocks():
-            livevars = set()
+            if not block.operations:
+                continue
+            for op in block.operations[:-1]:
+                assert not transactionbreak_analyzer.analyze(op)
+            op = block.operations[-1]
+            if not transactionbreak_analyzer.analyze(op):
+                continue
+            # This block ends in a transaction breaking operation.  So
+            # any variable passed from this block to a next one (with
+            # the exception of the variable freshly returned by the
+            # last operation) must be assumed to be potentially global.
             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)
+                for v1, v2 in zip(link.args, link.target.inputargs):
+                    if v1 is not op.result:
+                        yield v2
+
+def break_blocks_after_transaction_breaker(translator, graph,
+                                           transactionbreak_analyzer):
+    """Split blocks so that they end immediately after any operation
+    that may cause a transaction break."""
+    for block in list(graph.iterblocks()):
+        for i in range(len(block.operations)-2, -1, -1):
+            op = block.operations[i]
+            if transactionbreak_analyzer.analyze(op):
+                split_block(translator.annotator, block, i + 1)
 
 
 class GcSource(object):
@@ -153,12 +170,13 @@
     Constant, or a SpaceOperation that creates the value, or a string
     which describes a special case."""
 
-    def __init__(self, translator):
+    def __init__(self, translator, transactionbreak_analyzer=None):
         self.translator = translator
         self._backmapping = {}
         for v1, v2 in enum_gc_dependencies(translator):
             self._backmapping.setdefault(v2, []).append(v1)
-        for v2 in enum_transactionbroken_vars(translator):
+        for v2 in enum_transactionbroken_vars(translator,
+                                              transactionbreak_analyzer):
             self._backmapping.setdefault(v2, []).append('transactionbreak')
 
     def __getitem__(self, variable):
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
@@ -1,5 +1,7 @@
 from pypy.translator.translator import TranslationContext
 from pypy.translator.stm.gcsource import GcSource
+from pypy.translator.stm.gcsource import TransactionBreakAnalyzer
+from pypy.translator.stm.gcsource import break_blocks_after_transaction_breaker
 from pypy.objspace.flow.model import SpaceOperation, Constant
 from pypy.rpython.lltypesystem import lltype
 from pypy.rlib.jit import hint
@@ -10,11 +12,19 @@
         self.n = n
 
 
-def gcsource(func, sig):
+def gcsource(func, sig, transactionbreak=False):
     t = TranslationContext()
     t.buildannotator().build_types(func, sig)
     t.buildrtyper().specialize()
-    gsrc = GcSource(t)
+    if transactionbreak:
+        transactionbreak_analyzer = TransactionBreakAnalyzer(t)
+        transactionbreak_analyzer.analyze_all()
+        for graph in t.graphs:
+            break_blocks_after_transaction_breaker(
+                t, graph, transactionbreak_analyzer)
+    else:
+        transactionbreak_analyzer = None
+    gsrc = GcSource(t, transactionbreak_analyzer)
     return gsrc
 
 def test_simple():
@@ -159,7 +169,7 @@
         x = X(n)
         break_transaction()
         return x
-    gsrc = gcsource(main, [int])
+    gsrc = gcsource(main, [int], transactionbreak=True)
     v_result = gsrc.translator.graphs[0].getreturnvar()
     s = gsrc[v_result]
     assert 'transactionbreak' in s
@@ -168,7 +178,27 @@
         break_transaction()
         x = X(n)
         return x
-    gsrc = gcsource(main, [int])
+    gsrc = gcsource(main, [int], transactionbreak=True)
     v_result = gsrc.translator.graphs[0].getreturnvar()
     s = gsrc[v_result]
     assert 'transactionbreak' not in s
+    #
+    def main(n):
+        x = X(n)
+        break_transaction()
+        y = X(n)   # extra operation in the same block
+        return x
+    gsrc = gcsource(main, [int], transactionbreak=True)
+    v_result = gsrc.translator.graphs[0].getreturnvar()
+    s = gsrc[v_result]
+    assert 'transactionbreak' in s
+    #
+    def g(n):
+        break_transaction()
+        return X(n)
+    def main(n):
+        return g(n)
+    gsrc = gcsource(main, [int], transactionbreak=True)
+    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
@@ -3,6 +3,7 @@
 from pypy.annotation import model as annmodel
 from pypy.translator.unsimplify import varoftype, copyvar
 from pypy.translator.stm.localtracker import StmLocalTracker
+from pypy.translator.stm import gcsource
 from pypy.rpython.lltypesystem import lltype, lloperation
 from pypy.rpython import rclass
 
@@ -39,12 +40,22 @@
     def transform(self):
         assert not hasattr(self.translator, 'stm_transformation_applied')
         self.start_log()
-        for graph in self.translator.graphs:
+        t = self.translator
+        transactionbreak_analyzer = gcsource.TransactionBreakAnalyzer(t)
+        transactionbreak_analyzer.analyze_all()
+        #
+        for graph in t.graphs:
+            gcsource.break_blocks_after_transaction_breaker(
+                t, graph, self.transactionbreak_analyzer)
+        #
+        for graph in t.graphs:
             pre_insert_stm_writebarrier(graph)
-        self.localtracker = StmLocalTracker(self.translator)
-        for graph in self.translator.graphs:
+        #
+        self.localtracker = StmLocalTracker(t, transactionbreak_analyzer)
+        for graph in t.graphs:
             self.transform_graph(graph)
         self.localtracker = None
+        #
         self.translator.stm_transformation_applied = True
         self.print_logs()
 
@@ -253,7 +264,6 @@
     # one variable on which we do 'stm_writebarrier', but there are
     # also other variables that contain the same pointer, e.g. casted
     # to a different precise type.
-    from pypy.translator.stm.gcsource import COPIES_POINTER, _is_gc
     #
     def emit(op):
         for v1 in op.args:
@@ -277,9 +287,9 @@
         copies = {}
         wants_a_writebarrier = {}
         for op in block.operations:
-            if op.opname in COPIES_POINTER:
+            if op.opname in gcsource.COPIES_POINTER:
                 assert len(op.args) == 1
-                if _is_gc(op.result) and _is_gc(op.args[0]):
+                if gcsource._is_gc(op.result) and gcsource._is_gc(op.args[0]):
                     copies[op.result] = op
             elif (op.opname in ('getfield', 'getarrayitem',
                                 'getinteriorfield') and
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to