Author: Anton Gulenko <anton.gule...@googlemail.com> Branch: storage-context-state-v2 Changeset: r955:92d182dabea1 Date: 2014-07-25 16:33 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/92d182dabea1/
Log: Added the rest of the refactoring. diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py --- a/spyvm/interpreter.py +++ b/spyvm/interpreter.py @@ -1,7 +1,7 @@ import os from spyvm.shadow import MethodContextShadow, ActiveContext, InactiveContext, DirtyContext -from spyvm import model, constants, wrapper, objspace, interpreter_bytecodes +from spyvm import model, constants, wrapper, objspace, interpreter_bytecodes, error from rpython.rlib import jit, rstackovf, unroll @@ -17,6 +17,16 @@ self.s_target_context = s_target_context self.is_local = is_local +class NonVirtualReturn(Exception): + _attrs_ = ["s_target_context", "s_current_context", "value"] + def __init__(self, s_target_context, s_current_context, w_result): + self.value = w_result + self.s_target_context = s_target_context + self.s_current_context = s_current_context + + def print_trace(self): + print "\n====== Sender Chain Manipulation, contexts forced to heap at: %s" % self.s_current_context.short_str() + class LocalReturn(Exception): _attrs_ = ["value"] def __init__(self, value): @@ -25,14 +35,13 @@ class ContextSwitchException(Exception): """General Exception that causes the interpreter to leave the current context.""" - _attrs_ = ["s_new_context"] type = "ContextSwitch" def __init__(self, s_new_context): self.s_new_context = s_new_context - def print_trace(self, old_context): - print "====== %s, contexts forced to heap at: %s" % (self.type, self.s_new_context.short_str()) + def print_trace(self): + print "\n====== %s at: %s" % (self.type, self.s_new_context.short_str()) class StackOverflow(ContextSwitchException): """This causes the current jit-loop to be left, dumping all virtualized objects to the heap. @@ -43,17 +52,8 @@ class ProcessSwitch(ContextSwitchException): """This causes the interpreter to switch the executed context. Triggered when switching the process.""" + type = "Process Switch" - def print_trace(self, old_context): - print "====== Switched process from: %s" % old_context.short_str() - print "====== to: %s " % self.s_new_context.short_str() - -class SenderChainManipulation(ContextSwitchException): - """Manipulation of the sender chain can invalidate the jitted C stack. - We have to dump all virtual objects and rebuild the stack. - We try to raise this as rarely as possible and as late as possible.""" - type = "Sender Manipulation" - UNROLLING_BYTECODE_RANGES = unroll.unrolling_iterable(interpreter_bytecodes.BYTECODE_RANGES) def get_printable_location(pc, self, method): @@ -98,23 +98,27 @@ def loop(self, w_active_context): # This is the top-level loop and is not invoked recursively. - s_new_context = w_active_context.as_context_get_shadow(self.space) + s_context = w_active_context.as_context_get_shadow(self.space) while True: - s_sender = s_new_context.s_sender() + s_sender = s_context.s_sender() try: - self.stack_frame(s_new_context, None) + self.stack_frame(s_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 + e.print_trace() + s_context = e.s_new_context except LocalReturn, ret: - s_new_context = self.unwind_context_chain(s_sender, s_sender, ret.value) + s_context = self.unwind_context_chain(s_sender, s_sender, ret.value, "LocalReturn") except Return, ret: - s_new_context = self.unwind_context_chain(s_sender, ret.s_target_context, ret.value) + s_context = self.unwind_context_chain(s_sender, ret.s_target_context, ret.value, "Return") + except NonVirtualReturn, ret: + if self.is_tracing(): + ret.print_trace() + s_context = self.unwind_context_chain(ret.s_current_context, ret.s_target_context, ret.value, "NonVirtual") - # This is a wrapper around loop_bytecodes that cleanly enters/leaves the frame - # and handles the stack overflow protection mechanism. + # This is a wrapper around loop_bytecodes that cleanly enters/leaves the frame, + # handles the stack overflow protection mechanism and handles/dispatches Returns. def stack_frame(self, s_frame, s_sender, may_context_switch=True): try: if self.is_tracing(): @@ -129,17 +133,21 @@ rstackovf.check_stack_overflow() raise StackOverflow(s_frame) except Return, ret: - if ret.is_local: - raise LocalReturn(ret.value) + if s_frame.state is DirtyContext: + s_sender = s_frame.s_sender() # The sender has changed! + s_frame._activate_unwind_context(self) + target_context = s_sender if ret.is_local else ret.s_target_context + raise NonVirtualReturn(target_context, s_sender, ret.value) else: - raise ret + s_frame._activate_unwind_context(self) + if ret.s_target_context is s_sender or 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 @@ -164,14 +172,22 @@ except LocalReturn, ret: s_context.push(ret.value) - def unwind_context_chain(self, start_context, target_context, return_value): + def unwind_context_chain(self, start_context, target_context, return_value, source=""): 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." + if not context: + msg = "Context chain ended (source: %s) while trying to return\n%s\nfrom\n%s\n(pc %s)\nto\n%s\n(pc %s)" % ( + source, + return_value.as_repr_string(), + start_context.short_str(), + start_context.pc(), + target_context.short_str(), + start_context.pc()) + raise error.FatalError(msg) s_sender = context.s_sender() context._activate_unwind_context(self) context = s_sender diff --git a/spyvm/interpreter_bytecodes.py b/spyvm/interpreter_bytecodes.py --- a/spyvm/interpreter_bytecodes.py +++ b/spyvm/interpreter_bytecodes.py @@ -30,7 +30,8 @@ parameters += (self.fetch_next_bytecode(), ) i = i + 1 # This is a good place to step through bytecodes. - self.debug_bytecode() + + self.debug_bytecode(interp) return actual_implementation_method(self, interp, current_bytecode, *parameters) bytecode_implementation_wrapper.func_name = actual_implementation_method.func_name return bytecode_implementation_wrapper @@ -118,7 +119,7 @@ def pushLiteralVariableBytecode(self, interp, current_bytecode): # this bytecode assumes that literals[index] is an Association # which is an object with two named vars, and fetches the second - # named var (the value). + # named var (the value). index = current_bytecode & 31 w_association = self.w_method().getliteral(index) association = wrapper.AssociationWrapper(self.space, w_association) @@ -337,8 +338,6 @@ # ###################################################################### if interp.is_tracing(): interp.print_padded('-> %s %s' % (special_selector, s_frame.short_str())) - if not objectmodel.we_are_translated(): - import pdb; pdb.set_trace() return interp.stack_frame(s_frame, self) @@ -445,7 +444,6 @@ @bytecode_implementation(parameter_bytes=2) def doubleExtendedDoAnythingBytecode(self, interp, current_bytecode, second, third): - from spyvm.interpreter import SenderChainManipulation opType = second >> 5 if opType == 0: # selfsend @@ -467,16 +465,9 @@ association = wrapper.AssociationWrapper(self.space, w_association) self.push(association.value()) elif opType == 5: - # TODO - the following two special cases should not be necessary - try: - self.w_receiver().store(self.space, third, self.top()) - except SenderChainManipulation, e: - raise SenderChainManipulation(self) + self.w_receiver().store(self.space, third, self.top()) elif opType == 6: - try: - self.w_receiver().store(self.space, third, self.pop()) - except SenderChainManipulation, e: - raise SenderChainManipulation(self) + self.w_receiver().store(self.space, third, self.pop()) elif opType == 7: w_association = self.w_method().getliteral(third) association = wrapper.AssociationWrapper(self.space, w_association) @@ -607,7 +598,7 @@ bytecodePrimPointX = make_send_selector_bytecode("x", 0) bytecodePrimPointY = make_send_selector_bytecode("y", 0) - def debug_bytecode(self): + def debug_bytecode(self, interp): # Hook used in interpreter_debugging pass diff --git a/spyvm/interpreter_debugging.py b/spyvm/interpreter_debugging.py --- a/spyvm/interpreter_debugging.py +++ b/spyvm/interpreter_debugging.py @@ -49,8 +49,8 @@ @patch_context def debug_bytecode(original): - def meth(self): - if self.step_bytecodes: + def meth(self, interp): + if interp.step_bytecodes: _break() # Continue stepping from here to get to the current bytecode execution return meth _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit