[pypy-commit] pypy stm: - Refactor to support getfield of immutables.

arigo noreply at buildbot.pypy.org
Thu Oct 27 19:36:46 CEST 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: stm
Changeset: r48528:caa7e690cfc7
Date: 2011-10-27 17:05 +0200
http://bitbucket.org/pypy/pypy/changeset/caa7e690cfc7/

Log:	- Refactor to support getfield of immutables. That's enough to
	raise simple exceptions.

	- Complain when an exception leaves the frame in which we did
	begin_transaction().

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
@@ -1,4 +1,5 @@
-from pypy.rpython.llinterp import LLFrame
+from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.llinterp import LLFrame, LLException
 from pypy.translator.stm import rstm
 
 
@@ -26,35 +27,36 @@
 class LLSTMFrame(LLFrame):
 
     ALWAYS_ALLOW_OPERATIONS = set([
-        'int_*',
+        'int_*', 'same_as', 'cast_*',
         'direct_call',
         ])
-    ALLOW_WHEN_NOT_IN_TRANSACTION = set([
-        'stm_begin_transaction',
-        ])
-    ALLOW_WHEN_REGULAR_TRANSACTION = set([
-        'stm_getfield', 'stm_setfield',
-        'stm_commit_transaction',
-        ])
-    ALLOW_WHEN_INEVITABLE_TRANSACTION = ALLOW_WHEN_REGULAR_TRANSACTION.union([
-        ])
 
     def eval(self):
-        res = LLFrame.eval(self)
-        if (self.llinterpreter.stm_mode == "regular_transaction" and
-            self.llinterpreter.last_transaction_started_in_frame is self):
-            raise ReturnWithTransactionActive(self.graph)
+        try:
+            res = LLFrame.eval(self)
+        except LLException, e:
+            self.returning_from_frame_now()
+            raise e
+        self.returning_from_frame_now()
         return res
 
+    def returning_from_frame_now(self):
+        if (self.llinterpreter.stm_mode == "regular_transaction" and
+                self.llinterpreter.last_transaction_started_in_frame is self):
+            raise ReturnWithTransactionActive(self.graph)
+
     def getoperationhandler(self, opname):
-        stm_mode = self.llinterpreter.stm_mode
-        attrname = '_opstm_%s__%s' % (stm_mode, opname)
-        ophandler = getattr(self, attrname, None)
-        if ophandler is None:
-            self._validate_stmoperation_handler(stm_mode, opname)
-            ophandler = LLFrame.getoperationhandler(self, opname)
-            setattr(self, attrname, ophandler)
-        return ophandler
+        try:
+            return getattr(self, 'opstm_' + opname)
+        except AttributeError:
+            stm_mode = self.llinterpreter.stm_mode
+            attrname = '_opstm_%s__%s' % (stm_mode, opname)
+            ophandler = getattr(self, attrname, None)
+            if ophandler is None:
+                self._validate_stmoperation_handler(stm_mode, opname)
+                ophandler = LLFrame.getoperationhandler(self, opname)
+                setattr(self, attrname, ophandler)
+            return ophandler
 
     def _op_in_set(self, opname, set):
         if opname in set:
@@ -67,26 +69,42 @@
     def _validate_stmoperation_handler(self, stm_mode, opname):
         if self._op_in_set(opname, self.ALWAYS_ALLOW_OPERATIONS):
             return
-        allow = getattr(self, 'ALLOW_WHEN_' + stm_mode.upper())
-        if self._op_in_set(opname, allow):
-            return
         raise ForbiddenInstructionInSTMMode(stm_mode, opname, self.graph)
 
+    # ---------- operations that are sometimes safe ----------
+
+    def opstm_getfield(self, struct, fieldname):
+        STRUCT = lltype.typeOf(struct).TO
+        if STRUCT._immutable_field(fieldname):
+            # immutable field reads are always allowed
+            return LLFrame.op_getfield(self, struct, fieldname)
+        else:
+            # mutable 'getfields' are always forbidden for now
+            self.check_stm_mode(lambda m: False)
+            xxx
+
     # ---------- stm-only operations ----------
     # Note that for these tests we assume no real multithreading,
     # so that we just emulate the operations the easy way
 
-    def op_stm_getfield(self, struct, fieldname):
-        return self.op_getfield(struct, fieldname)
+    def check_stm_mode(self, checker):
+        stm_mode = self.llinterpreter.stm_mode
+        if not checker(stm_mode):
+            raise ForbiddenInstructionInSTMMode(stm_mode, self.graph)
 
-    def op_stm_setfield(self, struct, fieldname, value):
-        self.op_setfield(struct, fieldname, value)
+    def opstm_stm_getfield(self, struct, fieldname):
+        self.check_stm_mode(lambda m: m != "not_in_transaction")
+        return LLFrame.op_getfield(self, struct, fieldname)
 
-    def op_stm_begin_transaction(self):
-        assert self.llinterpreter.stm_mode == "not_in_transaction"
+    def opstm_stm_setfield(self, struct, fieldname, value):
+        self.check_stm_mode(lambda m: m != "not_in_transaction")
+        LLFrame.op_setfield(self, struct, fieldname, value)
+
+    def opstm_stm_begin_transaction(self):
+        self.check_stm_mode(lambda m: m == "not_in_transaction")
         self.llinterpreter.stm_mode = "regular_transaction"
         self.llinterpreter.last_transaction_started_in_frame = self
 
-    def op_stm_commit_transaction(self):
-        assert self.llinterpreter.stm_mode != "not_in_transaction"
+    def opstm_stm_commit_transaction(self):
+        self.check_stm_mode(lambda m: m != "not_in_transaction")
         self.llinterpreter.stm_mode = "not_in_transaction"
diff --git a/pypy/translator/stm/test/test_llstminterp.py b/pypy/translator/stm/test/test_llstminterp.py
--- a/pypy/translator/stm/test/test_llstminterp.py
+++ b/pypy/translator/stm/test/test_llstminterp.py
@@ -6,6 +6,9 @@
 from pypy.translator.stm.llstminterp import ReturnWithTransactionActive
 from pypy.translator.stm import rstm
 
+ALL_STM_MODES = ["not_in_transaction",
+                 "regular_transaction",
+                 "inevitable_transaction"]
 
 def test_simple():
     def func(n):
@@ -42,6 +45,18 @@
     res = eval_stm_graph(interp, graph, [p], stm_mode="inevitable_transaction")
     assert res == 42
 
+def test_getfield_immutable():
+    S = lltype.GcStruct('S', ('x', lltype.Signed), hints = {'immutable': True})
+    p = lltype.malloc(S, immortal=True)
+    p.x = 42
+    def func(p):
+        return p.x
+    interp, graph = get_interpreter(func, [p])
+    # a plain 'getfield' of an immutable field works in all modes
+    for mode in ALL_STM_MODES:
+        res = eval_stm_graph(interp, graph, [p], stm_mode=mode)
+        assert res == 42
+
 def test_begin_commit_transaction():
     S = lltype.GcStruct('S', ('x', lltype.Signed))
     p = lltype.malloc(S, immortal=True)
@@ -76,3 +91,18 @@
     interp, graph = get_interpreter(func, [])
     py.test.raises(ReturnWithTransactionActive,
                    eval_stm_graph, interp, graph, [])
+
+def test_cannot_raise_with_regular_transaction():
+    def g():
+        rstm.begin_transaction()
+        raise ValueError
+    g._dont_inline_ = True
+    def func():
+        try:
+            g()
+        except ValueError:
+            pass
+        rstm.commit_transaction()
+    interp, graph = get_interpreter(func, [])
+    py.test.raises(ReturnWithTransactionActive,
+                   eval_stm_graph, interp, graph, [])


More information about the pypy-commit mailing list