[pypy-commit] pypy stm-thread-2: The simplest version of read and write barrier insertion.
arigo
noreply at buildbot.pypy.org
Sun Sep 2 12:52:49 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch: stm-thread-2
Changeset: r57077:c9428658769d
Date: 2012-09-02 12:52 +0200
http://bitbucket.org/pypy/pypy/changeset/c9428658769d/
Log: The simplest version of read and write barrier insertion.
diff --git a/pypy/translator/stm/test/test_transform2.py b/pypy/translator/stm/test/test_transform2.py
new file mode 100644
--- /dev/null
+++ b/pypy/translator/stm/test/test_transform2.py
@@ -0,0 +1,125 @@
+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
diff --git a/pypy/translator/stm/transform2.py b/pypy/translator/stm/transform2.py
new file mode 100644
--- /dev/null
+++ b/pypy/translator/stm/transform2.py
@@ -0,0 +1,85 @@
+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
More information about the pypy-commit
mailing list