Armin Rigo avatar Armin Rigo committed c942865

The simplest version of read and write barrier insertion.

Comments (0)

Files changed (2)

pypy/translator/stm/test/test_transform2.py

+from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.llinterp import LLFrame
+from pypy.rpython.test.test_llinterp import get_interpreter, clear_tcache
+from pypy.translator.stm.transform2 import STMTransformer
+from pypy.conftest import option
+
+
+class BaseTestTransform(object):
+    prebuilt = ()
+
+    def interpret(self, fn, args):
+        clear_tcache()
+        self.stmstate = STMState(self.prebuilt)
+        interp, self.graph = get_interpreter(fn, args, view=False)
+        interp.stmstate = self.stmstate
+        interp.frame_class = LLSTMFrame
+        #
+        self.translator = interp.typer.annotator.translator
+        self.stmtransformer = STMTransformer(self.translator)
+        self.stmtransformer.transform()
+        if option.view:
+            self.translator.view()
+        #
+        result = interp.eval_graph(self.graph, args)
+        return result
+
+
+class STMState(object):
+    def __init__(self, prebuilt=()):
+        self.categories = {None: 'N'}   # Null
+        for p in prebuilt:
+            self.categories[self._getkey(p)] = 'G'   # Global
+        self.writemode = set()
+
+    def _getkey(self, p):
+        assert lltype.typeOf(p).TO._gckind == 'gc'
+        p = lltype.normalizeptr(p)
+        if p:
+            return p._obj0
+        else:
+            return None
+
+    def get_category(self, p):
+        key = self._getkey(p)
+        return self.categories[key]
+
+    def set_category(self, p, ncat):
+        key = self._getkey(p)
+        assert key is not None and ncat != 'N'
+        self.categories[key] = ncat
+        if ncat == 'W':
+            self.writemode.add(key)
+
+
+class LLSTMFrame(LLFrame):
+    _MORE_PRECISE_CATEGORIES = {
+        'P': 'PGORLWN',
+        'G': 'GN',
+        'O': 'ORLWN',
+        'R': 'RLWN',
+        'L': 'LWN',
+        'W': 'WN',
+        'N': 'N'}
+
+    def get_category(self, p):
+        return self.llinterpreter.stmstate.get_category(p)
+
+    def set_category(self, p, ncat):
+        self.llinterpreter.stmstate.set_category(p, ncat)
+
+    def check_category(self, p, expected):
+        cat = self.get_category(p)
+        assert cat in self._MORE_PRECISE_CATEGORIES[expected]
+
+    def op_stm_barrier(self, kind, obj):
+        frm, digittwo, to = kind
+        assert digittwo == '2'
+        self.check_category(obj, frm)
+        self.set_category(obj, to)
+        return obj
+
+    def op_getfield(self, obj, field):
+        self.check_category(obj, 'R')
+        return LLFrame.op_getfield(self, obj, field)
+
+    def op_setfield(self, obj, fieldname, fieldvalue):
+        self.check_category(obj, 'W')
+        return LLFrame.op_setfield(self, obj, fieldname, fieldvalue)
+
+
+class TestTransform(BaseTestTransform):
+
+    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
+        self.prebuilt = [x1, x2]
+
+        def f1(n):
+            if n > 1:
+                return x2.foo
+            else:
+                return x1.foo
+
+        res = self.interpret(f1, [4])
+        assert res == 81
+        assert len(self.stmstate.writemode) == 0
+        res = self.interpret(f1, [-5])
+        assert res == 42
+        assert len(self.stmstate.writemode) == 0
+
+    def test_simple_write(self):
+        X = lltype.GcStruct('X', ('foo', lltype.Signed))
+        x1 = lltype.malloc(X, immortal=True)
+        x1.foo = 42
+        self.prebuilt = [x1]
+
+        def f1(n):
+            x1.foo = n
+
+        self.interpret(f1, [4])
+        assert x1.foo == 4
+        assert len(self.stmstate.writemode) == 1

pypy/translator/stm/transform2.py

+from pypy.objspace.flow.model import SpaceOperation, Constant, Variable
+from pypy.objspace.flow.model import checkgraph
+from pypy.translator.unsimplify import varoftype
+from pypy.rpython.lltypesystem import lltype
+
+
+
+class STMTransformer(object):
+
+    def __init__(self, translator):
+        self.translator = translator
+
+    def transform(self):
+        assert not hasattr(self.translator, 'stm_transformation_applied')
+        self.start_log()
+        for graph in self.translator.graphs:
+            pre_insert_stm_barrier(self.translator, graph)
+        self.translator.stm_transformation_applied = True
+        self.print_logs()
+
+    def start_log(self):
+        from pypy.translator.c.support import log
+        log.info("Software Transactional Memory transformation")
+
+    def print_logs(self):
+        from pypy.translator.c.support import log
+        log.info("Software Transactional Memory transformation applied")
+
+
+
+def is_immutable(op):
+    if op.opname in ('getfield', 'setfield'):
+        STRUCT = op.args[0].concretetype.TO
+        return STRUCT._immutable_field(op.args[1].value)
+    if op.opname in ('getarrayitem', 'setarrayitem'):
+        ARRAY = op.args[0].concretetype.TO
+        return ARRAY._immutable_field()
+    if op.opname == 'getinteriorfield':
+        OUTER = op.args[0].concretetype.TO
+        return OUTER._immutable_interiorfield(unwraplist(op.args[1:]))
+    if op.opname == 'setinteriorfield':
+        OUTER = op.args[0].concretetype.TO
+        return OUTER._immutable_interiorfield(unwraplist(op.args[1:-1]))
+    if op.opname in ('gc_load', 'gc_store'):
+        return False
+    raise AssertionError(op)
+
+def pre_insert_stm_barrier(translator, graph):
+    for block in graph.iterblocks():
+        if block.operations == ():
+            continue
+        #
+        wants_a_barrier = {}
+        for op in block.operations:
+            if (op.opname in ('getfield', 'getarrayitem',
+                              'getinteriorfield', 'gc_load') and
+                  op.result.concretetype is not lltype.Void and
+                  op.args[0].concretetype.TO._gckind == 'gc' and
+                  not is_immutable(op)):
+                wants_a_barrier.setdefault(op, 'R')
+            elif (op.opname in ('setfield', 'setarrayitem',
+                                'setinteriorfield', 'gc_store') and
+                  op.args[-1].concretetype is not lltype.Void and
+                  op.args[0].concretetype.TO._gckind == 'gc' and
+                  not is_immutable(op)):
+                wants_a_barrier[op] = 'W'
+        #
+        if wants_a_barrier:
+            renamings = {}
+            newoperations = []
+            for op in block.operations:
+                to = wants_a_barrier.get(op)
+                if to is not None:
+                    c_info = Constant('P2%s' % to, lltype.Void)
+                    v = op.args[0]
+                    v = renamings.get(v, v)
+                    w = varoftype(v.concretetype)
+                    newop = SpaceOperation('stm_barrier', [c_info, v], w)
+                    newoperations.append(newop)
+                    renamings[op.args[0]] = w
+                newop = SpaceOperation(op.opname,
+                                       [renamings.get(v, v) for v in op.args],
+                                       op.result)
+                newoperations.append(newop)
+            block.operations = newoperations
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.