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