Author: Armin Rigo <ar...@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, []) _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit