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

Reply via email to