Author: Anton Gulenko <anton.gule...@googlemail.com> Branch: storage-context-state-v2 Changeset: r954:7292a07cb139 Date: 2014-07-25 11:07 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/7292a07cb139/
Log: Added part of the context state refactoring. diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py --- a/spyvm/interpreter.py +++ b/spyvm/interpreter.py @@ -12,10 +12,15 @@ class Return(Exception): _attrs_ = ["value", "s_target_context", "is_local"] - def __init__(self, s_target_context, w_result): + def __init__(self, s_target_context, w_result, is_local): self.value = w_result self.s_target_context = s_target_context - self.is_local = False + self.is_local = is_local + +class LocalReturn(Exception): + _attrs_ = ["value"] + def __init__(self, value): + self.value = value class ContextSwitchException(Exception): """General Exception that causes the interpreter to leave @@ -97,21 +102,44 @@ while True: s_sender = s_new_context.s_sender() try: - self.loop_bytecodes(s_new_context) + self.stack_frame(s_new_context, None) raise Exception("loop_bytecodes left without raising...") except ContextSwitchException, e: if self.is_tracing(): e.print_trace(s_new_context) s_new_context = e.s_new_context - except Return, nlr: - assert nlr.s_target_context or nlr.is_local - s_new_context = s_sender - if not nlr.is_local: - while s_new_context is not nlr.s_target_context: - s_sender = s_new_context.s_sender() - s_new_context._activate_unwind_context(self) - s_new_context = s_sender - s_new_context.push(nlr.value) + except LocalReturn, ret: + s_new_context = self.unwind_context_chain(s_sender, s_sender, ret.value) + except Return, ret: + s_new_context = self.unwind_context_chain(s_sender, ret.s_target_context, ret.value) + + # This is a wrapper around loop_bytecodes that cleanly enters/leaves the frame + # and handles the stack overflow protection mechanism. + def stack_frame(self, s_frame, s_sender, may_context_switch=True): + try: + if self.is_tracing(): + self.stack_depth += 1 + if s_frame._s_sender is None and s_sender is not None: + s_frame.store_s_sender(s_sender) + # Now (continue to) execute the context bytecodes + assert s_frame.state is InactiveContext + s_frame.state = ActiveContext + self.loop_bytecodes(s_frame, may_context_switch) + except rstackovf.StackOverflow: + rstackovf.check_stack_overflow() + raise StackOverflow(s_frame) + except Return, ret: + if ret.is_local: + raise LocalReturn(ret.value) + else: + raise ret + finally: + if self.is_tracing(): + self.stack_depth -= 1 + dirty_frame = s_frame.state is DirtyContext + s_frame.state = InactiveContext + if dirty_frame: + raise SenderChainManipulation(s_frame) def loop_bytecodes(self, s_context, may_context_switch=True): old_pc = 0 @@ -133,39 +161,22 @@ s_context=s_context) try: self.step(s_context) - except Return, nlr: - if nlr.s_target_context is s_context or nlr.is_local: - s_context.push(nlr.value) - else: - if nlr.s_target_context is None: - # This is the case where we are returning to our sender. - # Mark the return as local, so our sender will take it - nlr.is_local = True - s_context._activate_unwind_context(self) - raise nlr - - # This is a wrapper around loop_bytecodes that cleanly enters/leaves the frame - # and handles the stack overflow protection mechanism. - def stack_frame(self, s_frame, s_sender, may_context_switch=True): - try: - if self.is_tracing(): - self.stack_depth += 1 - if s_frame._s_sender is None and s_sender is not None: - s_frame.store_s_sender(s_sender) - # Now (continue to) execute the context bytecodes - assert s_frame.state is InactiveContext - s_frame.state = ActiveContext - self.loop_bytecodes(s_frame, may_context_switch) - except rstackovf.StackOverflow: - rstackovf.check_stack_overflow() - raise StackOverflow(s_frame) - finally: - if self.is_tracing(): - self.stack_depth -= 1 - dirty_frame = s_frame.state is DirtyContext - s_frame.state = InactiveContext - if dirty_frame: - raise SenderChainManipulation(s_frame) + except LocalReturn, ret: + s_context.push(ret.value) + + def unwind_context_chain(self, start_context, target_context, return_value): + if start_context is None: + # This is the toplevel frame. Execution ended. + raise ReturnFromTopLevel(return_value) + assert target_context + context = start_context + while context is not target_context: + assert context, "Sender chain ended without finding return-context." + s_sender = context.s_sender() + context._activate_unwind_context(self) + context = s_sender + context.push(return_value) + return context def step(self, context): bytecode = context.fetch_next_bytecode() diff --git a/spyvm/interpreter_bytecodes.py b/spyvm/interpreter_bytecodes.py --- a/spyvm/interpreter_bytecodes.py +++ b/spyvm/interpreter_bytecodes.py @@ -394,18 +394,13 @@ # it will find the sender as a local, and we don't have to # force the reference s_return_to = None - return_from_top = self.s_sender() is None + is_local = True else: s_return_to = self.s_home().s_sender() - return_from_top = s_return_to is None + is_local = False - if return_from_top: - # This should never happen while executing a normal image. - from spyvm.interpreter import ReturnFromTopLevel - raise ReturnFromTopLevel(return_value) - else: - from spyvm.interpreter import Return - raise Return(s_return_to, return_value) + from spyvm.interpreter import Return + raise Return(s_return_to, return_value, is_local) # ====== Send/Return bytecodes ====== @@ -508,16 +503,15 @@ if self.gettemp(1).is_nil(self.space): self.settemp(1, self.space.w_true) # mark unwound self.push(self.gettemp(0)) # push the first argument - from spyvm.interpreter import Return + from spyvm.interpreter import LocalReturn try: self.bytecodePrimValue(interp, 0) - except Return, nlr: - assert nlr.s_target_context or nlr.is_local - if self is not nlr.s_target_context and not nlr.is_local: - raise nlr + except LocalReturn: + # Local return value of ensure: block is ignored + pass finally: self.mark_returned() - + @bytecode_implementation() def unknownBytecode(self, interp, current_bytecode): raise error.MissingBytecode("unknownBytecode") _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit