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