Author: Armin Rigo <[email protected]>
Branch: stmgc-c4
Changeset: r67146:a692bbaba9aa
Date: 2013-10-04 05:49 +0200
http://bitbucket.org/pypy/pypy/changeset/a692bbaba9aa/
Log: Add 'with stm_ignored:' to not track in stm the reads and writes to
GC objects
diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py
--- a/rpython/rlib/objectmodel.py
+++ b/rpython/rlib/objectmodel.py
@@ -780,3 +780,37 @@
raise Exception("import_from_mixin: would overwrite the value "
"already defined locally for %r" % (key,))
target[key] = value
+
+# ____________________________________________________________
+
+class _StmIgnored:
+ def __enter__(self):
+ "NOT_RPYTHON"
+ def __exit__(self, *args):
+ "NOT_RPYTHON"
+
+class Entry(ExtRegistryEntry):
+ _about_ = _StmIgnored.__enter__.im_func
+ def compute_result_annotation(self, *args_s):
+ return None
+ def specialize_call(self, hop):
+ hop.exception_cannot_occur()
+ hop.genop('stm_ignored_start', [])
+
+class Entry(ExtRegistryEntry):
+ _about_ = _StmIgnored.__exit__.im_func
+ def compute_result_annotation(self, *args_s):
+ return None
+ def specialize_call(self, hop):
+ hop.exception_cannot_occur()
+ hop.genop('stm_ignored_stop', [])
+
+# Use "with stm_ignored:" around simple field read/write operations
+# that should not be tracked by the STM machinery. They are always
+# simply performed instead. It is useful for read/writes that don't
+# need to give a really consistent operation, when an approximative
+# behavior is fine, like incrementing some global counter.
+# XXX only for GC objects for now
+# XXX but it should replace 'stm_dont_track_raw_accesses' too
+# XXX DON'T USE for *writes* of a GC pointer into an object
+stm_ignored = _StmIgnored()
diff --git a/rpython/rtyper/lltypesystem/lloperation.py
b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -449,6 +449,9 @@
'stm_get_adr_of_private_rev_num':LLOp(),
'stm_get_adr_of_read_barrier_cache':LLOp(),
+ 'stm_ignored_start': LLOp(canrun=True),
+ 'stm_ignored_stop': LLOp(canrun=True),
+
# __________ address operations __________
'boehm_malloc': LLOp(),
diff --git a/rpython/rtyper/lltypesystem/opimpl.py
b/rpython/rtyper/lltypesystem/opimpl.py
--- a/rpython/rtyper/lltypesystem/opimpl.py
+++ b/rpython/rtyper/lltypesystem/opimpl.py
@@ -672,6 +672,12 @@
def op_debug_stm_flush_barrier():
pass
+def op_stm_ignored_start():
+ pass
+
+def op_stm_ignored_stop():
+ pass
+
def op_stm_ptr_eq(x, y):
return op_ptr_eq(x, y)
diff --git a/rpython/translator/c/funcgen.py b/rpython/translator/c/funcgen.py
--- a/rpython/translator/c/funcgen.py
+++ b/rpython/translator/c/funcgen.py
@@ -618,6 +618,12 @@
OP_STM_CLEAR_EXCEPTION_DATA_ON_ABORT= _OP_STM
OP_STM_ALLOCATE_NONMOVABLE_INT_ADR = _OP_STM
+ def OP_STM_IGNORED_START(self, op):
+ return '/* stm_ignored_start */'
+
+ def OP_STM_IGNORED_STOP(self, op):
+ return '/* stm_ignored_stop */'
+
def OP_PTR_NONZERO(self, op):
return '%s = (%s != NULL);' % (self.expr(op.result),
diff --git a/rpython/translator/c/test/test_standalone.py
b/rpython/translator/c/test/test_standalone.py
--- a/rpython/translator/c/test/test_standalone.py
+++ b/rpython/translator/c/test/test_standalone.py
@@ -918,6 +918,16 @@
self.compile(entry_point)
# assert did not explode
+ def test_ignore_stm_ignored(self):
+ from rpython.rlib.objectmodel import stm_ignored
+ def entry_point(argv):
+ with stm_ignored:
+ return len(argv)
+
+ self.compile(entry_point)
+ # assert did not explode
+
+
class TestMaemo(TestStandalone):
def setup_class(cls):
py.test.skip("TestMaemo: tests skipped for now")
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
@@ -530,6 +530,31 @@
self.interpret(f1, [])
assert self.barriers == ['I2W']
+ def test_stm_ignored_1(self):
+ from rpython.rlib.objectmodel import stm_ignored
+ class Foo:
+ bar = 0
+ x = Foo()
+ def f1():
+ with stm_ignored:
+ x.bar += 2
+
+ self.interpret(f1, [])
+ assert self.barriers == []
+
+ def test_stm_ignored_2(self):
+ from rpython.rlib.objectmodel import stm_ignored
+ class Foo:
+ bar = 0
+ def f1():
+ y = Foo()
+ llop.debug_stm_flush_barrier(lltype.Void)
+ with stm_ignored:
+ y.bar += 2
+
+ self.interpret(f1, [])
+ assert self.barriers == ['a2i']
+
external_release_gil = rffi.llexternal('external_release_gil', [], lltype.Void,
_callable=lambda: None,
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
@@ -66,6 +66,7 @@
class LLSTMFrame(LLFrame):
+ stm_ignored = False
def all_stm_ptrs(self):
for frame in self.llinterpreter.frame_stack:
@@ -80,6 +81,11 @@
cat = self.get_category_or_null(p)
assert cat is None or cat in 'AIQRVW'
if expected is not None:
+ if self.stm_ignored:
+ if expected >= 'W':
+ raise AssertionError("should not be seen in 'stm_ignored'")
+ if expected > 'I':
+ expected = 'I'
assert cat is not None and cat >= expected
return cat
@@ -99,6 +105,14 @@
self.llinterpreter.tester.barriers.append(kind)
return ptr2
+ def op_stm_ignored_start(self):
+ assert self.stm_ignored == False
+ self.stm_ignored = True
+
+ def op_stm_ignored_stop(self):
+ assert self.stm_ignored == True
+ self.stm_ignored = False
+
def op_stm_ptr_eq(self, obj1, obj2):
self.check_category(obj1, None)
self.check_category(obj2, None)
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
@@ -3,6 +3,7 @@
from rpython.translator.unsimplify import insert_empty_startblock
from rpython.rtyper.lltypesystem import lltype
from rpython.translator.backendopt.writeanalyze import top_set
+from rpython.translator.simplify import join_blocks
MALLOCS = set([
@@ -65,11 +66,12 @@
self.update_inputargs_category()
- def analyze_inside_block(self):
+ def analyze_inside_block(self, graph):
gcremovetypeptr = (
self.stmtransformer.translator.config.translation.gcremovetypeptr)
wants_a_barrier = {}
expand_comparison = set()
+ stm_ignored = False
for op in self.block.operations:
is_getter = (op.opname in ('getfield', 'getarrayitem',
'getinteriorfield', 'raw_load') and
@@ -118,7 +120,26 @@
elif op.opname == 'gc_writebarrier':
wants_a_barrier[op] = 'W'
+
+ elif op.opname == 'stm_ignored_start':
+ assert not stm_ignored, "nested 'with stm_ignored'"
+ stm_ignored = True
+
+ elif op.opname == 'stm_ignored_stop':
+ assert stm_ignored, "stm_ignored_stop without start?"
+ stm_ignored = False
+
+ if stm_ignored and op in wants_a_barrier:
+ if wants_a_barrier[op] == 'W':
+ raise Exception(
+ "%r: 'with stm_ignored:' contains unsupported "
+ "operation %r writing a GC pointer" % (graph, op))
+ assert 'I' <= wants_a_barrier[op] < 'W'
+ wants_a_barrier[op] = 'I'
#
+ if stm_ignored:
+ raise Exception("%r: 'with stm_ignored:' code body too complex"
+ % (graph,))
self.wants_a_barrier = wants_a_barrier
self.expand_comparison = expand_comparison
@@ -356,6 +377,7 @@
The letters are chosen so that a barrier is needed to change a
pointer from category x to category y if and only if y > x.
"""
+ join_blocks(graph)
graphinfo = stmtransformer.write_analyzer.compute_graph_info(graph)
annotator = stmtransformer.translator.annotator
insert_empty_startblock(annotator, graph)
@@ -366,7 +388,7 @@
if block.operations == ():
continue
bt = BlockTransformer(stmtransformer, block)
- bt.analyze_inside_block()
+ bt.analyze_inside_block(graph)
block_transformers[block] = bt
bt = block_transformers[graph.startblock]
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit