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