Author: Armin Rigo <[email protected]>
Branch: stm
Changeset: r51712:d8e6a730661d
Date: 2012-01-23 18:26 +0100
http://bitbucket.org/pypy/pypy/changeset/d8e6a730661d/

Log:    Implement proper immutability detection in {get,set}interiorfield().
        This lets *all* our RPython-level 'string[index]' be considered as
        immutable reads, which is likely essential for performance.

diff --git a/pypy/translator/stm/llstminterp.py 
b/pypy/translator/stm/llstminterp.py
--- a/pypy/translator/stm/llstminterp.py
+++ b/pypy/translator/stm/llstminterp.py
@@ -124,6 +124,38 @@
             self.check_stm_mode(lambda m: False)
             assert 0
 
+    def opstm_getinteriorfield(self, struct, *fields):
+        STRUCT = lltype.typeOf(struct).TO
+        if STRUCT._immutable_interiorfield(fields):
+            # immutable field reads are always allowed
+            return LLFrame.op_getinteriorfield(self, struct, *fields)
+        elif STRUCT._gckind == 'raw':
+            # raw getfields are allowed outside a regular transaction
+            self.check_stm_mode(lambda m: m != "regular_transaction")
+            return LLFrame.op_getinteriorfield(self, struct, *fields)
+        else:
+            # mutable 'getfields' are always forbidden for now
+            self.check_stm_mode(lambda m: False)
+            assert 0
+
+    def opstm_setinteriorfield(self, struct, *fields_and_newvalue):
+        fields = fields_and_newvalue[:-1]
+        newvalue = fields_and_newvalue[-1]
+        STRUCT = lltype.typeOf(struct).TO
+        if STRUCT._immutable_interiorfield(fields):
+            # immutable field writes (i.e. initializing writes) should
+            # always be fine, because they should occur into newly malloced
+            # structures
+            LLFrame.op_setinteriorfield(self, struct, *fields_and_newvalue)
+        elif STRUCT._gckind == 'raw':
+            # raw setfields are allowed outside a regular transaction
+            self.check_stm_mode(lambda m: m != "regular_transaction")
+            LLFrame.op_setinteriorfield(self, struct, *fields_and_newvalue)
+        else:
+            # mutable 'setfields' are always forbidden for now
+            self.check_stm_mode(lambda m: False)
+            assert 0
+
     def opstm_malloc(self, TYPE, flags):
         # non-GC must not occur in a regular transaction,
         # but can occur in inevitable mode or outside a transaction
diff --git a/pypy/translator/stm/test/test_transform.py 
b/pypy/translator/stm/test/test_transform.py
--- a/pypy/translator/stm/test/test_transform.py
+++ b/pypy/translator/stm/test/test_transform.py
@@ -98,8 +98,11 @@
     assert summary(graph) == {'stm_setarrayitem': 1}
     eval_stm_graph(interp, graph, [p], stm_mode="regular_transaction")
 
+STRLIKE = lltype.GcStruct('STRLIKE',    # no 'immutable' in this version
+                          ('chars', lltype.Array(lltype.Char)))
+
 def test_getinteriorfield():
-    p = lltype.malloc(rstr.STR, 100, immortal=True)
+    p = lltype.malloc(STRLIKE, 100, immortal=True)
     p.chars[42] = 'X'
     def func(p):
         return p.chars[42]
@@ -110,12 +113,32 @@
     assert res == 'X'
 
 def test_setinteriorfield():
+    p = lltype.malloc(STRLIKE, 100, immortal=True)
+    def func(p):
+        p.chars[42] = 'Y'
+    interp, graph = get_interpreter(func, [p])
+    transform_graph(graph)
+    assert summary(graph) == {'stm_setinteriorfield': 1}
+    res = eval_stm_graph(interp, graph, [p], stm_mode="regular_transaction")
+
+def test_getstrchar():
+    p = lltype.malloc(rstr.STR, 100, immortal=True)
+    p.chars[42] = 'X'
+    def func(p):
+        return p.chars[42]
+    interp, graph = get_interpreter(func, [p])
+    transform_graph(graph)
+    assert summary(graph) == {'getinteriorfield': 1}
+    res = eval_stm_graph(interp, graph, [p], stm_mode="regular_transaction")
+    assert res == 'X'
+
+def test_setstrchar():
     p = lltype.malloc(rstr.STR, 100, immortal=True)
     def func(p):
         p.chars[42] = 'Y'
     interp, graph = get_interpreter(func, [p])
     transform_graph(graph)
-    assert summary(graph) == {'stm_setinteriorfield': 1}
+    assert summary(graph) == {'setinteriorfield': 1}
     res = eval_stm_graph(interp, graph, [p], stm_mode="regular_transaction")
 
 def test_unsupported_operation():
diff --git a/pypy/translator/stm/transform.py b/pypy/translator/stm/transform.py
--- a/pypy/translator/stm/transform.py
+++ b/pypy/translator/stm/transform.py
@@ -164,7 +164,7 @@
         OUTER = op.args[0].concretetype.TO
         if op.result.concretetype is lltype.Void:
             op1 = op
-        elif OUTER._hints.get('immutable'):
+        elif OUTER._immutable_interiorfield(unwraplist(op.args[1:])):
             op1 = op
         elif OUTER._gckind == 'raw':
             turn_inevitable(newoperations, "getinteriorfield-raw")
@@ -177,7 +177,7 @@
         OUTER = op.args[0].concretetype.TO
         if op.args[-1].concretetype is lltype.Void:
             op1 = op
-        elif OUTER._hints.get('immutable'):
+        elif OUTER._immutable_interiorfield(unwraplist(op.args[1:-1])):
             op1 = op
         elif OUTER._gckind == 'raw':
             turn_inevitable(newoperations, "setinteriorfield-raw")
@@ -232,3 +232,12 @@
 def turn_inevitable_and_proceed(newoperations, op):
     turn_inevitable(newoperations, op.opname)
     newoperations.append(op)
+
+def unwraplist(list_v):
+    for v in list_v:
+        if isinstance(v, Constant):
+            yield v.value
+        elif isinstance(v, Variable):
+            yield None    # unknown
+        else:
+            raise AssertionError(v)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to