Author: Armin Rigo <[email protected]>
Branch: stmgc-c7
Changeset: r69868:1783f387a615
Date: 2014-03-11 18:01 +0100
http://bitbucket.org/pypy/pypy/changeset/1783f387a615/
Log: Write a minimal "readbarrier.py".
diff --git a/rpython/memory/gctransform/stmframework.py
b/rpython/memory/gctransform/stmframework.py
--- a/rpython/memory/gctransform/stmframework.py
+++ b/rpython/memory/gctransform/stmframework.py
@@ -53,6 +53,7 @@
hop.genop("stm_pop_root_into", [var])
def transform_generic_set(self, hop):
+ # XXX detect if we're inside a 'stm_ignored' block and... do what?
assert self.write_barrier_ptr == "stm"
opname = hop.spaceop.opname
v_struct = hop.spaceop.args[0]
diff --git a/rpython/translator/stm/breakfinder.py
b/rpython/translator/stm/breakfinder.py
--- a/rpython/translator/stm/breakfinder.py
+++ b/rpython/translator/stm/breakfinder.py
@@ -1,17 +1,21 @@
from rpython.translator.backendopt import graphanalyze
+from rpython.translator.stm import funcgen
TRANSACTION_BREAK = set([
'stm_commit_transaction',
- 'stm_begin_inevitable_transaction',
- 'stm_perform_transaction',
- 'stm_partial_commit_and_resume_other_threads', # new priv_revision
- 'jit_assembler_call',
- 'jit_stm_transaction_break_point',
+ 'stm_start_inevitable_transaction',
+ #'stm_perform_transaction',
+ #'stm_partial_commit_and_resume_other_threads', # new priv_revision
+ #'jit_assembler_call',
+ #'jit_stm_transaction_break_point',
'stm_enter_callback_call',
'stm_leave_callback_call',
])
+for tb in TRANSACTION_BREAK:
+ assert hasattr(funcgen, tb)
+
class TransactionBreakAnalyzer(graphanalyze.BoolGraphAnalyzer):
diff --git a/rpython/translator/stm/readbarrier.py
b/rpython/translator/stm/readbarrier.py
new file mode 100644
--- /dev/null
+++ b/rpython/translator/stm/readbarrier.py
@@ -0,0 +1,31 @@
+from rpython.flowspace.model import SpaceOperation
+from rpython.translator.unsimplify import varoftype
+from rpython.rtyper.lltypesystem import lltype
+
+
+READ_OPS = set(['getfield', 'getarrayitem', 'getinteriorfield', 'raw_load'])
+
+
+def is_gc_ptr(T):
+ return isinstance(T, lltype.Ptr) and T.TO._gckind == 'gc'
+
+
+def insert_stm_read_barrier(transformer, graph):
+ # We need to put enough 'stm_read' in the graph so that any
+ # execution of a READ_OP on some GC object is guaranteed to also
+ # execute either 'stm_read' or 'stm_write' on the same GC object
+ # during the same transaction.
+ #
+ # XXX this can be optimized a lot, but for now we go with the
+ # simplest possible solution...
+ #
+ for block in graph.iterblocks():
+ if not block.operations:
+ continue
+ newops = []
+ for op in block.operations:
+ if op.opname in READ_OPS and is_gc_ptr(op.args[0].concretetype):
+ v_none = varoftype(lltype.Void)
+ newops.append(SpaceOperation('stm_read', [op.args[0]], v_none))
+ newops.append(op)
+ block.operations = newops
diff --git a/rpython/translator/stm/test/test_readbarrier.py
b/rpython/translator/stm/test/test_readbarrier.py
new file mode 100644
--- /dev/null
+++ b/rpython/translator/stm/test/test_readbarrier.py
@@ -0,0 +1,26 @@
+from rpython.translator.stm.test.transform_support import BaseTestTransform
+from rpython.rtyper.lltypesystem import lltype
+
+
+class TestReadBarrier(BaseTestTransform):
+ do_read_barrier = True
+
+ def test_simple_read(self):
+ X = lltype.GcStruct('X', ('foo', lltype.Signed))
+ x1 = lltype.malloc(X, immortal=True)
+ x1.foo = 42
+ x2 = lltype.malloc(X, immortal=True)
+ x2.foo = 81
+
+ def f1(n):
+ if n > 1:
+ return x2.foo
+ else:
+ return x1.foo
+
+ res = self.interpret(f1, [4])
+ assert res == 81
+ assert self.read_barriers == [x2]
+ res = self.interpret(f1, [-5])
+ assert res == 42
+ assert self.read_barriers == [x1]
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
@@ -2,7 +2,6 @@
from rpython.rtyper.llinterp import LLFrame
from rpython.rtyper.test.test_llinterp import get_interpreter, clear_tcache
from rpython.translator.stm.transform import STMTransformer
-from rpython.translator.stm.writebarrier import needs_barrier
from rpython.conftest import option
@@ -21,13 +20,12 @@
class BaseTestTransform(object):
- do_write_barrier = False
+ do_read_barrier = False
do_turn_inevitable = False
do_jit_driver = False
def build_state(self):
- self.writemode = set()
- self.barriers = []
+ self.read_barriers = []
def get_category_or_null(self, p):
if isinstance(p, _stmptr):
@@ -41,7 +39,8 @@
def interpret(self, fn, args, gcremovetypeptr=False, run=True):
self.build_state()
clear_tcache()
- interp, self.graph = get_interpreter(fn, args, view=False)
+ interp, self.graph = get_interpreter(fn, args, view=False,
+ viewbefore=False)
interp.tester = self
interp.frame_class = LLSTMFrame
#
@@ -50,8 +49,8 @@
self.stmtransformer = STMTransformer(self.translator)
if self.do_jit_driver:
self.stmtransformer.transform_jit_driver()
- if self.do_write_barrier:
- self.stmtransformer.transform_write_barrier()
+ if self.do_read_barrier:
+ self.stmtransformer.transform_read_barrier()
if self.do_turn_inevitable:
self.stmtransformer.transform_turn_inevitable()
if option.view:
@@ -68,64 +67,39 @@
class LLSTMFrame(LLFrame):
stm_ignored = False
+ def eval(self):
+ self.gcptrs_actually_read = []
+ result = LLFrame.eval(self)
+ for x in self.gcptrs_actually_read:
+ assert x in self.llinterpreter.tester.read_barriers
+ return result
+
def all_stm_ptrs(self):
for frame in self.llinterpreter.frame_stack:
for value in frame.bindings.values():
if isinstance(value, _stmptr):
yield value
- def get_category_or_null(self, p):
- return self.llinterpreter.tester.get_category_or_null(p)
+ def op_stm_read(self, obj):
+ self.llinterpreter.tester.read_barriers.append(obj)
- def check_category(self, p, expected):
- 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
-
- def op_stm_barrier(self, kind, obj):
- frm, middledigit, to = kind
- assert middledigit == '2'
- cat = self.check_category(obj, frm)
- if not needs_barrier(cat, to):
- # a barrier, but with no effect
- self.llinterpreter.tester.barriers.append(kind.lower())
- return obj
- else:
- # a barrier, calling a helper
- ptr2 = _stmptr(obj, to)
- if to >= 'V':
- self.llinterpreter.tester.writemode.add(ptr2._obj)
- self.llinterpreter.tester.barriers.append(kind)
- return ptr2
+ def op_stm_write(self, obj):
+ self.op_stm_read(obj) # implicitly counts as a read barrier too
def op_stm_ignored_start(self):
+ xxx
assert self.stm_ignored == False
self.stm_ignored = True
def op_stm_ignored_stop(self):
+ xxx
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)
- self.llinterpreter.tester.barriers.append('=')
- return obj1 == obj2
-
def op_getfield(self, obj, field):
if obj._TYPE.TO._gckind == 'gc':
if obj._TYPE.TO._immutable_field(field):
- expected = 'I'
- else:
- expected = 'R'
- self.check_category(obj, expected)
+ self.gcptrs_actually_read.append(obj)
return LLFrame.op_getfield(self, obj, field)
def op_setfield(self, obj, fieldname, fieldvalue):
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
@@ -1,4 +1,5 @@
from rpython.translator.stm.inevitable import insert_turn_inevitable
+from rpython.translator.stm.readbarrier import insert_stm_read_barrier
from rpython.translator.stm.jitdriver import reorganize_around_jit_driver
from rpython.translator.stm.threadlocalref import transform_tlref
from rpython.translator.c.support import log
@@ -13,6 +14,7 @@
assert not hasattr(self.translator, 'stm_transformation_applied')
self.start_log()
self.transform_jit_driver()
+ self.transform_read_barrier()
self.transform_turn_inevitable()
self.print_logs()
self.translator.stm_transformation_applied = True
@@ -21,6 +23,12 @@
self.transform_threadlocalref()
self.print_logs_after_gc()
+ def transform_read_barrier(self):
+ self.read_barrier_counts = 0
+ for graph in self.translator.graphs:
+ insert_stm_read_barrier(self, graph)
+ log("%d read barriers inserted" % (self.read_barrier_counts,))
+
def transform_turn_inevitable(self):
for graph in self.translator.graphs:
insert_turn_inevitable(graph)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit